Some changes for v4.0.0 (locations finder + biome sampling + area input change)

* added biome samples filter to check biome proportions (#173, #266)
* added outline display for the area of selected conditions (WIP)
* added "from-visible" to conditions editor (#271)
* added Locations to Search tab, to look for positions in the current seed
* moved Tiggers to Search tab
* changed area/position input fields to use block coordinates (#265)
* changed spiral iterator to use an arbitrary, user defined step size
* fixed octave options and added generated display texts (#253)
This commit is contained in:
Cubitect 2024-01-07 11:54:31 +01:00
parent 08f04345e8
commit 01fa7069b3
40 changed files with 1981 additions and 885 deletions

View File

@ -1,7 +1,7 @@
# Cubiomes Viewer Build Instructions
Cubiomes Viewer is a Qt5 application and requires:
* Qt5.9 or newer (Qt6 is not supported) and a
* Qt5.9 or newer (Qt6 might work, but isn't currently supported) and a
* GNU C++ compiler (GCC or Clang).
The cubiomes library is included as a submodule to this repository.

@ -1 +1 @@
Subproject commit 6b36603d2dc31f6ef8a3d4746c9b64ad3ace0a00
Subproject commit c3ff21a1a8b6bf362221db3f4dee71a0dc7dba9b

View File

@ -32,6 +32,10 @@ win32: {
static_gnu: {
LIBS += -static -static-libgcc -static-libstdc++
}
sanitizer: {
QMAKE_CFLAGS += -fsanitize=undefined
LIBS += -lubsan -ldl
}
gcc {
greaterThan(QMAKE_GCC_MAJOR_VERSION, 9): QMAKE_CXXFLAGS += -Wno-deprecated-copy
@ -39,10 +43,6 @@ gcc {
CONFIG(debug, debug|release): {
CUTARGET = debug
!win32 {
QMAKE_CFLAGS += -fsanitize=undefined
LIBS += -lubsan -ldl
}
} else {
CUTARGET = release
}
@ -115,6 +115,7 @@ SOURCES += \
src/search.cpp \
src/searchthread.cpp \
src/tabbiomes.cpp \
src/tablocations.cpp \
src/tabstructures.cpp \
src/tabtriggers.cpp \
src/mainwindow.cpp \
@ -182,6 +183,7 @@ HEADERS += \
src/searchthread.h \
src/seedtables.h \
src/tabbiomes.h \
src/tablocations.h \
src/tabstructures.h \
src/tabtriggers.h \
src/mainwindow.h \
@ -206,6 +208,7 @@ FORMS += \
src/mainwindow.ui \
src/rangedialog.ui \
src/tabbiomes.ui \
src/tablocations.ui \
src/tabstructures.ui \
src/tabtriggers.ui

View File

@ -9,11 +9,11 @@
<name>Cubiomes Viewer</name>
<summary>An efficient Minecraft seed finder and map viewer.</summary>
<description>
<p>Cubiomes Viewer offers highly customizable seed-finding utilities and a map viewer for the biome and structure generation of Minecraft Java Edition for the main releases up to 1.19.</p>
<p>Cubiomes Viewer offers highly customizable seed-finding utilities and a map viewer for the biome and structure generation of Minecraft Java Edition for the main releases up to 1.21.</p>
</description>
<releases>
<release version="3.4.2" date="2024-01-02">
<release version="4.0.dev0" date="2024-01.??">
</release>
</releases>

View File

@ -2116,7 +2116,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter
--------------------------------------------------------------------------- */
QSplitter {
background-color: #455364;
background-color: #19232D; /*#455364;*/
spacing: 0px;
padding: 0px;
margin: 0px;

View File

@ -4,9 +4,9 @@
#include <QDialog>
#include <QString>
#define VERS_MAJOR 3
#define VERS_MINOR 4
#define VERS_PATCH 2 // negative patch number designates a development version
#define VERS_MAJOR 4
#define VERS_MINOR 0
#define VERS_PATCH -1 // negative patch number designates a development version
// returns +1 if newer, -1 if older and 0 if equal
inline int cmpVers(int major, int minor, int patch)

View File

@ -21,29 +21,16 @@
#include <QFontMetricsF>
static QString getTip(int mc, int layer, uint32_t flags, int id)
{
uint64_t mL = 0, mM = 0;
genPotential(&mL, &mM, layer, mc, flags, id);
QString tip = ConditionDialog::tr("Generates any of:");
for (int j = 0; j < 64; j++)
if (mL & (1ULL << j))
tip += QString("\n") + getBiomeDisplay(mc, j);
for (int j = 0; j < 64; j++)
if (mM & (1ULL << j))
tip += QString("\n") + getBiomeDisplay(mc, 128+j);
return tip;
}
#define WARNING_CHAR QChar(0x26A0)
ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcversion, QListWidgetItem *item, Condition *initcond)
ConditionDialog::ConditionDialog(FormConditions *parent, MapView *mapview, Config *config, WorldInfo wi, QListWidgetItem *item, Condition *initcond)
: QDialog(parent, Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint)
, ui(new Ui::ConditionDialog)
, luahash()
, mapview(mapview)
, config(config)
, item(item)
, mc(mcversion)
, wi(wi)
{
memset(&cond, 0, sizeof(cond));
ui->setupUi(this);
@ -55,7 +42,7 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
textDescription->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
ui->collapseDescription->init(tr("Description/Notes"), textDescription, true);
const char *p_mcs = mc2str(mc);
const char *p_mcs = mc2str(wi.mc);
QString mcs = tr("MC %1", "Minecraft version").arg(p_mcs ? p_mcs : "?");
ui->labelMC->setText(mcs);
@ -86,20 +73,20 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
if (c.save == initcond->save)
continue;
if (c.save == initcond->relative)
initindex = ui->comboBoxRelative->count();
initindex = ui->comboRelative->count();
}
QString condstr = c.summary(false).simplified();
ui->comboBoxRelative->addItem(condstr, c.save);
ui->comboRelative->addItem(condstr, c.save);
}
if (initindex < 0)
{
if (initcond && initcond->relative > 0)
{
initindex = ui->comboBoxRelative->count();
initindex = ui->comboRelative->count();
QString condstr = QString("[%1] %2 broken reference")
.arg(initcond->relative, 2, 10, QChar('0'))
.arg(WARNING_CHAR);
ui->comboBoxRelative->addItem(condstr, initcond->relative);
ui->comboRelative->addItem(condstr, initcond->relative);
}
else
{
@ -117,6 +104,8 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
ui->lineSquare->setValidator(uintval);
ui->lineRadius->setValidator(uintval);
ui->lineSpiralStep->setValidator(new QIntValidator(1, 0xffff, this));
ui->lineBiomeSize->setValidator(new QIntValidator(1, INT_MAX, this));
ui->lineTolerance->setValidator(new QIntValidator(0, 255, this));
@ -125,28 +114,31 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
ui->lineMin->setValidator(new QDoubleValidator(-1e6, 1e6, 4, this));
ui->lineMax->setValidator(new QDoubleValidator(-1e6, 1e6, 4, this));
ui->comboBoxCat->setItemDelegate(new ComboBoxDelegate(this, ui->comboBoxCat));
ui->comboBoxType->setItemDelegate(new ComboBoxDelegate(this, ui->comboBoxType));
ui->lineCoverage->setValidator(new QDoubleValidator(0.0001, 100.0000, 4, this));
ui->lineConfidence->setValidator(new QDoubleValidator(0.0001, 99.9999, 4, this));
//qobject_cast<QListView*>(ui->comboBoxCat->view())->setSpacing(1);
//qobject_cast<QListView*>(ui->comboBoxType->view())->setSpacing(1);
ui->comboCat->setItemDelegate(new ComboBoxDelegate(this, ui->comboCat));
ui->comboType->setItemDelegate(new ComboBoxDelegate(this, ui->comboType));
ui->comboBoxCat->addItem(tr("Select category"));
ui->comboBoxCat->insertSeparator(1);
ui->comboBoxCat->addItem(getPix("helper"), tr("Algorithm helpers"), CAT_HELPER);
ui->comboBoxCat->addItem(getPix("quad"), tr("Quad-structure"), CAT_QUAD);
ui->comboBoxCat->addItem(getPix("stronghold"), tr("Structures"), CAT_STRUCT);
ui->comboBoxCat->addItem(getPix("overworld"), tr("Biomes"), CAT_BIOMES);
ui->comboBoxCat->addItem(getPix("nether"), tr("Nether biomes"), CAT_NETHER);
ui->comboBoxCat->addItem(getPix("the_end"), tr("End biomes"), CAT_END);
ui->comboBoxCat->addItem(getPix("slime"), tr("Other"), CAT_OTHER);
int fmh = ui->comboBoxCat->fontMetrics().height() + 8;
ui->comboBoxCat->setIconSize(QSize(fmh, fmh));
ui->comboBoxType->setIconSize(QSize(fmh, fmh));
//qobject_cast<QListView*>(ui->comboCat->view())->setSpacing(1);
//qobject_cast<QListView*>(ui->comboType->view())->setSpacing(1);
ui->comboCat->addItem(tr("Select category"));
ui->comboCat->insertSeparator(1);
ui->comboCat->addItem(getPix("helper"), tr("Algorithm helpers"), CAT_HELPER);
ui->comboCat->addItem(getPix("quad"), tr("Quad-structure"), CAT_QUAD);
ui->comboCat->addItem(getPix("stronghold"), tr("Structures"), CAT_STRUCT);
ui->comboCat->addItem(getPix("overworld"), tr("Biomes"), CAT_BIOMES);
ui->comboCat->addItem(getPix("nether"), tr("Nether biomes"), CAT_NETHER);
ui->comboCat->addItem(getPix("the_end"), tr("End biomes"), CAT_END);
ui->comboCat->addItem(getPix("slime"), tr("Other"), CAT_OTHER);
int fmh = ui->comboCat->fontMetrics().height() + 8;
ui->comboCat->setIconSize(QSize(fmh, fmh));
ui->comboType->setIconSize(QSize(fmh, fmh));
for (int i = 0; i < 256; i++)
{
QString bname = getBiomeDisplay(mc, i);
QString bname = getBiomeDisplay(wi.mc, i);
if (bname.isEmpty())
continue;
QCheckBox *cb = new QCheckBox(bname);
@ -214,7 +206,7 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
if (i == NP_DEPTH)
{
LabeledRange *lr;
if (mc <= MC_1_17)
if (wi.mc <= MC_1_17)
lr = new LabeledRange(this, 0, 256);
else
lr = new LabeledRange(this, -64, 320);
@ -253,15 +245,15 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
std::vector<int> ids;
for (int id = 0; id < 256; id++)
ids.push_back(id);
IdCmp cmp(IdCmp::SORT_LEX, mc, DIM_UNDEF);
IdCmp cmp(IdCmp::SORT_LEX, wi.mc, DIM_UNDEF);
std::sort(ids.begin(), ids.end(), cmp);
for (int id : ids)
{
const int *lim = getBiomeParaLimits(mc, id);
const int *lim = getBiomeParaLimits(wi.mc, id);
if (!lim)
continue;
NoiseBiomeIndicator *cb = new NoiseBiomeIndicator(getBiomeDisplay(mc, id), this);
NoiseBiomeIndicator *cb = new NoiseBiomeIndicator(getBiomeDisplay(wi.mc, id), this);
QString tip = "<pre>";
for (int j = 0; j < NP_MAX; j++)
{
@ -310,6 +302,8 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
ui->checkSkipRef->setChecked(false);
ui->radioSquare->setChecked(true);
ui->checkRadius->setChecked(false);
ui->lineCoverage->setText("100");
ui->lineConfidence->setText("95");
onCheckStartChanged(false);
on_comboClimatePara_currentIndexChanged(0);
@ -328,22 +322,25 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
ui->comboLua->setCurrentIndex(-1); // force index change
ui->comboLua->setCurrentIndex(ui->comboLua->findData(QVariant::fromValue(cond.hash)));
ui->comboBoxCat->setCurrentIndex(ui->comboBoxCat->findData(ft.cat));
for (int i = 0; i < ui->comboBoxType->count(); i++)
ui->comboCat->setCurrentIndex(ui->comboCat->findData(ft.cat));
for (int i = 0; i < ui->comboType->count(); i++)
{
int type = ui->comboBoxType->itemData(i, Qt::UserRole).toInt();
int type = ui->comboType->itemData(i, Qt::UserRole).toInt();
if (type == cond.type)
{
ui->comboBoxType->setCurrentIndex(i);
ui->comboType->setCurrentIndex(i);
break;
}
}
ui->comboBoxRelative->setCurrentIndex(initindex);
on_comboBoxRelative_activated(initindex);
ui->comboRelative->setCurrentIndex(initindex);
on_comboRelative_activated(initindex);
ui->textEditLua->document()->setModified(false);
ui->comboMatchBiome->insertItem(0, getBiomeDisplay(mc, cond.biomeId), QVariant::fromValue(cond.biomeId));
if (cond.step)
ui->lineSpiralStep->setText(QString::number(cond.step));
ui->comboMatchBiome->insertItem(0, getBiomeDisplay(wi.mc, cond.biomeId), QVariant::fromValue(cond.biomeId));
ui->comboMatchBiome->setCurrentIndex(0);
ui->comboClimatePara->setCurrentIndex(ui->comboClimatePara->findData(QVariant::fromValue(cond.para)));
@ -364,6 +361,10 @@ ConditionDialog::ConditionDialog(FormConditions *parent, Config *config, int mcv
ui->checkApprox->setChecked(cond.flags & Condition::FLG_APPROX);
ui->checkMatchAny->setChecked(cond.flags & Condition::FLG_MATCH_ANY);
ui->lineCoverage->setText(QString::number(cond.converage ? cond.converage * 100 : 100));
ui->lineConfidence->setText(QString::number(cond.confidence ? cond.confidence * 100 : 95));
ui->checkSamplePos->setChecked(cond.count == 1);
int i, n = ui->comboY->count();
for (i = 0; i < n; i++)
if (ui->comboY->itemText(i).section(' ', 0, 0).toInt() == cond.y)
@ -475,26 +476,40 @@ void ConditionDialog::addTempCat(int temp, QString name)
int r = temp % Special;
ui->gridLayoutTemps->addWidget(tempsboxes[temp], r, c * 2 + 0);
ui->gridLayoutTemps->addWidget(l, r, c * 2 + 1);
if (mc > MC_1_6 && mc <= MC_1_17)
l->setToolTip(getTip(mc, L_SPECIAL_1024, 0, r + (temp >= Special ? 256 : 0)));
if (wi.mc > MC_1_6 && wi.mc <= MC_1_17)
{
uint64_t mL = 0, mM = 0;
genPotential(&mL, &mM, L_SPECIAL_1024, wi.mc, 0, r + (temp >= Special ? 256 : 0));
QString tip = ConditionDialog::tr("Generates any of:");
for (int j = 0; j < 64; j++)
if (mL & (1ULL << j))
tip += QString("\n") + getBiomeDisplay(wi.mc, j);
for (int j = 0; j < 64; j++)
if (mM & (1ULL << j))
tip += QString("\n") + getBiomeDisplay(wi.mc, 128+j);
l->setToolTip(tip);
}
}
void ConditionDialog::updateMode()
{
int filterindex = ui->comboBoxType->currentData().toInt();
int filterindex = ui->comboType->currentData().toInt();
const FilterInfo &ft = g_filterinfo.list[filterindex];
ui->lineSummary->setPlaceholderText(QApplication::translate("Filter", ft.name));
QPalette pal;
if (mc < ft.mcmin || mc > ft.mcmax)
if (wi.mc < ft.mcmin || wi.mc > ft.mcmax)
pal.setColor(QPalette::Normal, QPalette::Button, QColor(255,0,0,127));
ui->comboBoxType->setPalette(pal);
ui->comboType->setPalette(pal);
ui->groupBoxGeneral->setEnabled(filterindex != F_SELECT);
ui->groupBoxPosition->setEnabled(filterindex != F_SELECT);
ui->checkRadius->setEnabled(ft.rmax);
ui->checkRadius->setEnabled(ft.loc & FilterInfo::LOC_R);
bool p1 = ft.loc & FilterInfo::LOC_1;
bool p2 = ft.loc & FilterInfo::LOC_2;
if (ui->checkRadius->isEnabled() && ui->checkRadius->isChecked())
{
@ -516,28 +531,44 @@ void ConditionDialog::updateMode()
}
else
{
bool custom = ui->radioCustom->isChecked();
ui->lineRadius->setEnabled(false);
ui->radioSquare->setEnabled(ft.area);
ui->radioCustom->setEnabled(ft.area);
ui->radioSquare->setEnabled(p2);
ui->radioCustom->setEnabled(p2);
ui->lineSquare->setEnabled(!custom && ft.area);
ui->labelX1->setEnabled(ft.coord && (custom || !ft.area));
ui->labelZ1->setEnabled(ft.coord && (custom || !ft.area));
ui->labelX2->setEnabled(custom && ft.area);
ui->labelZ2->setEnabled(custom && ft.area);
ui->lineEditX1->setEnabled(ft.coord && (custom || !ft.area));
ui->lineEditZ1->setEnabled(ft.coord && (custom || !ft.area));
ui->lineEditX2->setEnabled(custom && ft.area);
ui->lineEditZ2->setEnabled(custom && ft.area);
if (ui->radioCustom->isChecked())
{
ui->lineSquare->setEnabled(false);
ui->labelX1->setEnabled(p1);
ui->labelZ1->setEnabled(p1);
ui->labelX2->setEnabled(p2);
ui->labelZ2->setEnabled(p2);
ui->lineEditX1->setEnabled(p1);
ui->lineEditZ1->setEnabled(p1);
ui->lineEditX2->setEnabled(p2);
ui->lineEditZ2->setEnabled(p2);
}
else
{
ui->lineSquare->setEnabled(p2);
ui->labelX1->setEnabled(p1 && !p2);
ui->labelZ1->setEnabled(p1 && !p2);
ui->labelX2->setEnabled(false);
ui->labelZ2->setEnabled(false);
ui->lineEditX1->setEnabled(p1 && !p2);
ui->lineEditZ1->setEnabled(p1 && !p2);
ui->lineEditX2->setEnabled(false);
ui->lineEditZ2->setEnabled(false);
}
}
ui->labelSpinBox->setEnabled(ft.count);
ui->spinBox->setEnabled(ft.count);
ui->checkSkipRef->setEnabled(ft.count);
ui->buttonFromVisible->setEnabled(mapview && p2 && ui->comboRelative->currentIndex() == 0);
bool cnt = ft.branch == FilterInfo::BR_CLUST;
ui->labelSpinBox->setEnabled(cnt);
ui->spinBox->setEnabled(cnt);
ui->checkSkipRef->setEnabled(cnt);
ui->labelY->setEnabled(ft.hasy);
ui->comboY->setEnabled(ft.hasy);
@ -561,14 +592,18 @@ void ConditionDialog::updateMode()
else if (ft.cat == CAT_BIOMES || ft.cat == CAT_NETHER || ft.cat == CAT_END)
{
ui->stackedWidget->setCurrentWidget(ui->pageBiomes);
ui->checkApprox->setEnabled(mc <= MC_1_17 || ft.step == 4);
ui->checkApprox->setEnabled(wi.mc <= MC_1_17 || ft.grid == 4);
ui->checkMatchAny->setEnabled(true);
if (filterindex == F_BIOME_SAMPLE)
ui->stackedBiome->setCurrentWidget(ui->pageBiomeOptSample);
else
ui->stackedBiome->setCurrentWidget(ui->pageBiomeOpt);
}
else if (filterindex == F_VILLAGE)
{
ui->stackedWidget->setCurrentWidget(ui->pageVillage);
ui->checkStartPieces->setEnabled(mc >= MC_1_14);
ui->checkAbandoned->setEnabled(filterindex == F_VILLAGE && mc >= MC_1_10);
ui->checkStartPieces->setEnabled(wi.mc >= MC_1_14);
ui->checkAbandoned->setEnabled(filterindex == F_VILLAGE && wi.mc >= MC_1_10);
}
else if (filterindex == F_FORTRESS)
{
@ -578,22 +613,22 @@ void ConditionDialog::updateMode()
else if (filterindex == F_BASTION)
{
ui->stackedWidget->setCurrentWidget(ui->pageBastion);
ui->checkStartBastion->setEnabled(mc >= MC_1_16_1);
ui->checkStartBastion->setEnabled(wi.mc >= MC_1_16_1);
}
else if (filterindex == F_PORTAL || filterindex == F_PORTALN)
{
ui->stackedWidget->setCurrentWidget(ui->pagePortal);
ui->checkStartPortal->setEnabled(mc >= MC_1_16_1);
ui->checkStartPortal->setEnabled(wi.mc >= MC_1_16_1);
}
else if (filterindex == F_ENDCITY)
{
ui->stackedWidget->setCurrentWidget(ui->pageEndCity);
ui->checkBasement->setEnabled(mc >= MC_1_9);
ui->checkBasement->setEnabled(wi.mc >= MC_1_9);
}
else if (filterindex == F_IGLOO)
{
ui->stackedWidget->setCurrentWidget(ui->pageIgloo);
ui->checkEndShip->setEnabled(mc >= MC_1_9);
ui->checkEndShip->setEnabled(wi.mc >= MC_1_9);
}
else if (filterindex == F_HEIGHT)
{
@ -603,6 +638,10 @@ void ConditionDialog::updateMode()
{
ui->stackedWidget->setCurrentWidget(ui->pageLua);
}
else if (filterindex == F_SPIRAL)
{
ui->stackedWidget->setCurrentWidget(ui->pageSpiral);
}
else
{
ui->stackedWidget->setCurrentWidget(ui->pageNone);
@ -610,26 +649,14 @@ void ConditionDialog::updateMode()
updateBiomeSelection();
QString loc = "";
QString areatip = "";
QString lowtip = "";
QString uptip = "";
QString loc = tr("Location");
QString areatip = tr("From floor(-x/2) to floor(x/2) on both axes (inclusive)");
QString lowtip = tr("Lower bound (inclusive)");
QString uptip = tr("Upper bound (inclusive)");
if (ft.grid > 1)
loc += " " + tr("(sampled on a grid of scale 1:%1)").arg(ft.grid);
if (ft.step > 1)
{
QString multxt = QString("%1%2").arg(QChar(0xD7)).arg(ft.step);
loc = tr("Location (coordinates are multiplied by %1)").arg(multxt);
areatip = tr("From floor(-x/2)%1 to floor(x/2)%1 on both axes (inclusive)").arg(multxt);
lowtip = tr("Lower bound %1 (inclusive)").arg(multxt);
uptip = tr("Upper bound %1 (inclusive)").arg(multxt);
}
else
{
loc = tr("Location");
areatip = tr("From floor(-x/2) to floor(x/2) on both axes (inclusive)");
lowtip = tr("Lower bound (inclusive)");
uptip = tr("Upper bound (inclusive)");
}
ui->groupBoxPosition->setTitle(loc);
ui->radioSquare->setToolTip(areatip);
ui->labelX1->setToolTip(lowtip);
@ -646,7 +673,7 @@ void ConditionDialog::updateMode()
void ConditionDialog::updateBiomeSelection()
{
int filterindex = ui->comboBoxType->currentData().toInt();
int filterindex = ui->comboType->currentData().toInt();
const FilterInfo &ft = g_filterinfo.list[filterindex];
// clear tool tips
@ -669,14 +696,14 @@ void ConditionDialog::updateBiomeSelection()
available.push_back(cold_ocean);
available.push_back(frozen_ocean);
}
else if (ft.cat == CAT_BIOMES && mc > MC_B1_7 && mc <= MC_1_17)
else if (ft.cat == CAT_BIOMES && wi.mc > MC_B1_7 && wi.mc <= MC_1_17)
{
int layerId = ft.layer;
if (layerId == 0)
{
Generator tmp;
setupGenerator(&tmp, mc, 0);
const Layer *l = getLayerForScale(&tmp, ft.step);
setupGenerator(&tmp, wi.mc, 0);
const Layer *l = getLayerForScale(&tmp, ft.grid);
if (l)
layerId = l - tmp.ls.layers;
}
@ -688,7 +715,7 @@ void ConditionDialog::updateBiomeSelection()
QCheckBox *cb = it.second;
uint64_t mL = 0, mM = 0;
uint32_t flags = 0;
genPotential(&mL, &mM, layerId, mc, flags, it.first);
genPotential(&mL, &mM, layerId, wi.mc, flags, it.first);
if (mL || mM)
{
@ -699,12 +726,12 @@ void ConditionDialog::updateBiomeSelection()
for (int j = 0; j < 64; j++)
{
if (mL & (1ULL << j))
tip += QString("\n") + getBiomeDisplay(mc, j);
tip += QString("\n") + getBiomeDisplay(wi.mc, j);
}
for (int j = 0; j < 64; j++)
{
if (mM & (1ULL << j))
tip += QString("\n") + getBiomeDisplay(mc, j+128);
tip += QString("\n") + getBiomeDisplay(wi.mc, j+128);
}
cb->setToolTip(tip);
}
@ -719,12 +746,12 @@ void ConditionDialog::updateBiomeSelection()
{
for (const auto& it : biomecboxes)
{
if (isOverworld(mc, it.first))
if (isOverworld(wi.mc, it.first))
available.push_back(it.first);
}
}
IdCmp cmp = {IdCmp::SORT_LEX, mc, DIM_UNDEF};
IdCmp cmp = {IdCmp::SORT_LEX, wi.mc, DIM_UNDEF};
std::sort(available.begin(), available.end(), cmp);
if (ui->stackedWidget->currentWidget() == ui->pageBiomes)
@ -772,7 +799,7 @@ void ConditionDialog::updateBiomeSelection()
for (int id: available)
{
QString s = getBiomeDisplay(mc, id);
QString s = getBiomeDisplay(wi.mc, id);
ui->comboMatchBiome->addItem(getBiomeIcon(id), s, QVariant::fromValue(id));
allowed_matches.append(s);
}
@ -785,7 +812,7 @@ void ConditionDialog::updateBiomeSelection()
}
else
{
QString s = QString("%1 %2").arg(WARNING_CHAR).arg(getBiomeDisplay(mc, curid.toInt()));
QString s = QString("%1 %2").arg(WARNING_CHAR).arg(getBiomeDisplay(wi.mc, curid.toInt()));
ui->comboMatchBiome->insertItem(0, getBiomeIcon(curid.toInt(), true), s, curid);
ui->comboMatchBiome->setCurrentIndex(0);
allowed_matches.append(s);
@ -830,21 +857,25 @@ int ConditionDialog::warnIfBad(Condition cond)
}
else if (cond.type == F_BIOME_CENTER || cond.type == F_BIOME_CENTER_256)
{
int w = cond.x2 - cond.x1 + 1;
int h = cond.z2 - cond.z1 + 1;
int s = ft.pow2;
int w = (cond.x2 >> s) - (cond.x1 >> s) + 1;
int h = (cond.z2 >> s) - (cond.z1 >> s) + 1;
if ((unsigned int)(w * h) < cond.count * cond.biomeSize)
{
QString text = tr(
"The biome locator checks for %1 instances of size %2 each, "
"which cannot be satisfied by an area of size %3%4%5 = %6.")
.arg(cond.count).arg(cond.biomeSize).arg(w).arg(QChar(0xD7)).arg(h).arg(w * h);
"The biome locator checks for %n instance(s), each of size %1, "
"which cannot be satisfied by an area of size\n"
"%2%3%4 = %5 < %6 @ scale 1:%7.", "", cond.count)
.arg(cond.biomeSize)
.arg(w).arg(QChar(0xD7)).arg(h).arg(w*h)
.arg(cond.count * cond.biomeSize).arg(1<<s);
warn(this, tr("Area Insufficient"), text);
return QMessageBox::Cancel;
}
}
else if (ft.cat == CAT_BIOMES)
{
if (mc >= MC_1_18)
if (wi.mc >= MC_1_18)
{
uint64_t m = cond.biomeToFindM;
uint64_t underground =
@ -890,8 +921,8 @@ void ConditionDialog::onAccept()
Condition c = cond;
c.version = Condition::VER_CURRENT;
c.type = ui->comboBoxType->currentData().toInt();
c.relative = ui->comboBoxRelative->currentData().toInt();
c.type = ui->comboType->currentData().toInt();
c.relative = ui->comboRelative->currentData().toInt();
c.count = ui->spinBox->value();
c.skipref = ui->checkSkipRef->isChecked();
@ -923,19 +954,21 @@ void ConditionDialog::onAccept()
c.z2 = ui->lineEditZ2->text().toInt();
}
if (ft.area)
if (ft.loc & FilterInfo::LOC_2)
{
if (c.x1 > c.x2) std::swap(c.x1, c.x2);
if (c.z1 > c.z2) std::swap(c.z1, c.z2);
}
if (ui->checkRadius->isChecked())
if (ui->checkRadius->isEnabled() && ui->checkRadius->isChecked())
c.rmax = ui->lineRadius->text().toInt() + 1;
else
c.rmax = 0;
c.y = ui->comboY->currentText().section(' ', 0, 0).toInt();
c.step = ui->lineSpiralStep->text().toUShort();
if (ui->stackedWidget->currentWidget() == ui->pageBiomes)
{
c.biomeToFind = c.biomeToFindM = 0;
@ -959,7 +992,9 @@ void ConditionDialog::onAccept()
}
}
}
c.count = 0;
c.count = ui->checkSamplePos->isChecked() ? 1 : 0;
c.converage = ui->lineCoverage->text().toFloat() / 100.0;
c.confidence = ui->lineConfidence->text().toFloat() / 100.0;
}
if (ui->stackedWidget->currentWidget() == ui->pageBiomeCenter)
{
@ -1029,17 +1064,18 @@ void ConditionDialog::onAccept()
close();
}
void ConditionDialog::on_comboBoxType_activated(int)
void ConditionDialog::on_comboType_activated(int)
{
updateMode();
}
void ConditionDialog::on_comboBoxRelative_activated(int)
void ConditionDialog::on_comboRelative_activated(int)
{
QPalette pal;
if (ui->comboBoxRelative->currentText().contains(WARNING_CHAR))
if (ui->comboRelative->currentText().contains(WARNING_CHAR))
pal.setColor(QPalette::Normal, QPalette::Button, QColor(255,0,0,127));
ui->comboBoxRelative->setPalette(pal);
ui->comboRelative->setPalette(pal);
updateMode();
}
void ConditionDialog::on_buttonUncheck_clicked()
@ -1073,21 +1109,34 @@ void ConditionDialog::on_buttonAreaInfo_clicked()
"</p><p>"
"Alternatively, the area can be defined as a <b>centered square</b> "
"with a certain side length. In this case the area has the bounds: "
"[-X/2, -X/2] on both axes, rounding down and bounds included. For "
"[-X/2, +X/2] on both axes, rounding down and bounds included. For "
"example a centered square with side 3 will go from -2 to 1 for both "
"the X and Z axes."
"</p><p>"
"Important to note is that some filters have a scaling associated with "
"them. This means that the area is not defined in blocks, but on a grid "
"with the given spacing (such as chunks instead of blocks). A scaling "
"of 1:16, for example, means that the aforementioned centered square of "
"side 3 will range from -32 to 31 in block coordinates. (Chunk 1 has "
"blocks 16 to 31.)"
"them. This means the condition only checks on a grid with that spacing. "
"An area with a range from -21 to 21 at scale 1:16 may effectively be "
"expanded to -32 to 31, and get sampled at -32, -16, 0 and 16."
"</p></body></html>"
));
mb.exec();
}
void ConditionDialog::on_buttonFromVisible_clicked()
{
if (!mapview)
return;
int x1, z1, x2, z2;
mapview->getVisible(&x1, &z1, &x2, &z2);
ui->lineEditX1->setText(QString::number(x1));
ui->lineEditZ1->setText(QString::number(z1));
ui->lineEditX2->setText(QString::number(x2));
ui->lineEditZ2->setText(QString::number(z2));
ui->checkRadius->setChecked(false);
ui->radioCustom->setChecked(true);
updateMode();
}
void ConditionDialog::on_checkRadius_toggled(bool)
{
updateMode();
@ -1121,15 +1170,15 @@ void ConditionDialog::on_ConditionDialog_finished(int result)
item = 0;
}
void ConditionDialog::on_comboBoxCat_currentIndexChanged(int)
void ConditionDialog::on_comboCat_currentIndexChanged(int)
{
int cat = ui->comboBoxCat->currentData().toInt();
ui->comboBoxType->setEnabled(cat != CAT_NONE);
ui->comboBoxType->clear();
int cat = ui->comboCat->currentData().toInt();
ui->comboType->setEnabled(cat != CAT_NONE);
ui->comboType->clear();
int slot = 0;
ui->comboBoxType->insertItem(slot, tr("Select type"), QVariant::fromValue((int)F_SELECT));
ui->comboBoxType->insertSeparator(++slot);
ui->comboType->insertItem(slot, tr("Select type"), QVariant::fromValue((int)F_SELECT));
ui->comboType->insertSeparator(++slot);
const FilterInfo *ft_list[FILTER_MAX] = {};
const FilterInfo *ft;
@ -1150,16 +1199,16 @@ void ConditionDialog::on_comboBoxCat_currentIndexChanged(int)
QVariant vidx = QVariant::fromValue((int)(ft - g_filterinfo.list));
QString txt = QApplication::translate("Filter", ft->name);
if (ft->icon)
ui->comboBoxType->insertItem(slot, getPix(ft->icon), txt, vidx);
ui->comboType->insertItem(slot, getPix(ft->icon), txt, vidx);
else
ui->comboBoxType->insertItem(slot, txt, vidx);
ui->comboType->insertItem(slot, txt, vidx);
if (mc < ft->mcmin || mc > ft->mcmax)
ui->comboBoxType->setItemData(slot, false, Qt::UserRole-1); // deactivate
if (wi.mc < ft->mcmin || wi.mc > ft->mcmax)
ui->comboType->setItemData(slot, false, Qt::UserRole-1); // deactivate
if (ft == g_filterinfo.list + F_FORTRESS)
ui->comboBoxType->insertSeparator(slot++);
ui->comboType->insertSeparator(slot++);
if (ft == g_filterinfo.list + F_ENDCITY)
ui->comboBoxType->insertSeparator(slot++);
ui->comboType->insertSeparator(slot++);
}
updateMode();
@ -1253,8 +1302,8 @@ void ConditionDialog::onClimateLimitChanged()
getClimateLimits(limok, limex);
getPossibleBiomesForLimits(ok, mc, limok);
getPossibleBiomesForLimits(ex, mc, limex);
getPossibleBiomesForLimits(ok, wi.mc, limok);
getPossibleBiomesForLimits(ex, wi.mc, limex);
for (auto& it : noisebiomes)
{
@ -1270,7 +1319,7 @@ void ConditionDialog::onClimateLimitChanged()
void ConditionDialog::on_lineBiomeSize_textChanged(const QString &)
{
int filterindex = ui->comboBoxType->currentData().toInt();
int filterindex = ui->comboType->currentData().toInt();
double area = ui->lineBiomeSize->text().toInt();
QString s;
if (filterindex == F_BIOME_CENTER_256)
@ -1368,7 +1417,7 @@ void ConditionDialog::on_pushLuaSaveAs_clicked()
stream.flush();
file.close();
ui->textEditLua->document()->setModified(false);
uint64_t hash = getScriptHash(fnam);
uint64_t hash = getScriptHash(QFileInfo(fnam));
ui->comboLua->addItem(QFileInfo(fnam).baseName(), QVariant::fromValue(hash));
ui->comboLua->setCurrentIndex(ui->comboLua->count() - 1);
}
@ -1495,17 +1544,21 @@ void ConditionDialog::on_comboClimatePara_currentIndexChanged(int)
{
ui->comboOctaves->clear();
int loptidx = LOPT_NOISE_PARA + ui->comboClimatePara->currentData().toInt();
QStringList items;
for (int i = 0; ; i++)
{
if (const char *s = getLayerOptionText(loptidx, i))
items.append(s);
else
LayerOptInfo info;
if (!getLayerOptionInfo(&info, loptidx, i, wi))
break;
ui->comboOctaves->addItem(info.summary);
ui->comboOctaves->setItemData(ui->comboOctaves->count()-1, info.tooltip, Qt::ToolTipRole);
}
ui->comboOctaves->addItems(items);
on_comboOctaves_currentIndexChanged(0);
}
void ConditionDialog::on_comboOctaves_currentIndexChanged(int)
{
ui->comboOctaves->setToolTip(ui->comboOctaves->currentData(Qt::ToolTipRole).toString());
}
void ConditionDialog::on_comboY_currentTextChanged(const QString &text)
{

View File

@ -19,6 +19,7 @@
#include <QStandardItemModel>
class MainWindow;
class MapView;
namespace Ui {
class ConditionDialog;
@ -180,7 +181,7 @@ class ConditionDialog : public QDialog
public:
explicit ConditionDialog(FormConditions *parent, Config *config, int mc, QListWidgetItem *item = 0, Condition *initcond = 0);
explicit ConditionDialog(FormConditions *parent, MapView *mapview, Config *config, WorldInfo wi, QListWidgetItem *item = 0, Condition *initcond = 0);
virtual ~ConditionDialog();
void addTempCat(int temp, QString name);
@ -199,15 +200,16 @@ signals:
void setCond(QListWidgetItem *item, Condition cond, int modified);
private slots:
void on_comboBoxType_activated(int);
void on_comboType_activated(int);
void on_comboBoxRelative_activated(int);
void on_comboRelative_activated(int);
void on_buttonUncheck_clicked();
void on_buttonInclude_clicked();
void on_buttonExclude_clicked();
void on_buttonAreaInfo_clicked();
void on_buttonFromVisible_clicked();
void on_checkRadius_toggled(bool checked);
void on_radioSquare_toggled(bool checked);
@ -218,7 +220,7 @@ private slots:
void on_ConditionDialog_finished(int result);
void on_comboBoxCat_currentIndexChanged(int);
void on_comboCat_currentIndexChanged(int);
void onCheckStartChanged(int state);
void onClimateLimitChanged();
@ -236,6 +238,7 @@ private slots:
void on_pushInfoLua_clicked();
void on_comboClimatePara_currentIndexChanged(int index);
void on_comboOctaves_currentIndexChanged(int index);
void on_comboY_currentTextChanged(const QString &text);
void on_comboY2_currentTextChanged(const QString &text);
@ -255,10 +258,11 @@ private:
uint64_t luahash;
public:
MapView *mapview;
Config *config;
QListWidgetItem *item;
Condition cond;
int mc;
WorldInfo wi;
};
#endif // CONDITIONDIALOG_H

View File

@ -13,7 +13,7 @@
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="4">
<widget class="QComboBox" name="comboBoxCat">
<widget class="QComboBox" name="comboCat">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>2</horstretch>
@ -26,7 +26,7 @@
</widget>
</item>
<item row="0" column="5">
<widget class="QComboBox" name="comboBoxType">
<widget class="QComboBox" name="comboType">
<property name="enabled">
<bool>false</bool>
</property>
@ -256,6 +256,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonFromVisible">
<property name="text">
<string>From visible</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="6">
@ -344,7 +351,7 @@ QPushButton:hover {
</widget>
</item>
<item row="6" column="3" colspan="4">
<widget class="QComboBox" name="comboBoxRelative">
<widget class="QComboBox" name="comboRelative">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
@ -388,7 +395,7 @@ QPushButton:hover {
<number>0</number>
</property>
<property name="currentIndex">
<number>5</number>
<number>1</number>
</property>
<widget class="QWidget" name="pageNone">
<property name="enabled">
@ -460,47 +467,7 @@ QPushButton:hover {
<string>Biomes</string>
</property>
<layout class="QGridLayout" name="gridLayout_13">
<item row="0" column="0">
<widget class="QCheckBox" name="checkApprox">
<property name="toolTip">
<string>Enables optimizations that trade some accuracy for speed</string>
</property>
<property name="text">
<string>Approximate</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkMatchAny">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style=&quot;white-space:pre&quot;&gt;Satisfied if &lt;span style=&quot; font-weight:600;&quot;&gt;any&lt;/span&gt; of the checked biomes are present&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Match any</string>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3">
<widget class="QLabel" name="labelY">
<property name="text">
<string>Sample at height (Y):</string>
</property>
</widget>
</item>
<item row="0" column="4">
<item row="0" column="5">
<widget class="QComboBox" name="comboY">
<property name="editable">
<bool>true</bool>
@ -565,7 +532,24 @@ QPushButton:hover {
</item>
</widget>
</item>
<item row="1" column="0" colspan="5">
<item row="3" column="0" colspan="6">
<widget class="QScrollArea" name="scrollBiomes">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollBiomesContent">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
</property>
<item>
<layout class="QGridLayout" name="gridLayoutBiomes"/>
</item>
</layout>
</widget>
</widget>
</item>
<item row="2" column="0" colspan="6">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="buttonUncheck">
@ -590,21 +574,128 @@ QPushButton:hover {
</item>
</layout>
</item>
<item row="2" column="0" colspan="5">
<widget class="QScrollArea" name="scrollBiomes">
<property name="widgetResizable">
<bool>true</bool>
<item row="0" column="3">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="scrollBiomesContent">
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="sizeConstraint">
<enum>QLayout::SetMinAndMaxSize</enum>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" rowspan="2" colspan="2">
<widget class="QStackedWidget" name="stackedBiome">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="pageBiomeOpt">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_30">
<property name="leftMargin">
<number>0</number>
</property>
<item>
<layout class="QGridLayout" name="gridLayoutBiomes"/>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="0">
<widget class="QCheckBox" name="checkMatchAny">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style=&quot;white-space:pre&quot;&gt;Satisfied if &lt;span style=&quot; font-weight:600;&quot;&gt;any&lt;/span&gt; of the checked biomes are present&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Match any</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkApprox">
<property name="toolTip">
<string>Enables optimizations that trade some accuracy for speed</string>
</property>
<property name="text">
<string>Approximate</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="pageBiomeOptSample">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout_31">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>Coverage (%):</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Confidence (%):</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QCheckBox" name="checkSamplePos">
<property name="text">
<string>Yield positions</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineCoverage"/>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineConfidence"/>
</item>
</layout>
</widget>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="labelY">
<property name="text">
<string>Sample at height (Y):</string>
</property>
</widget>
</item>
</layout>
@ -1325,6 +1416,58 @@ QPushButton:hover {
</item>
</layout>
</widget>
<widget class="QWidget" name="pageSpiral">
<layout class="QGridLayout" name="gridLayout_28">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QGroupBox" name="groupBoxSpiral">
<property name="title">
<string>Spiral iterator</string>
</property>
<layout class="QGridLayout" name="gridLayout_29">
<item row="0" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Step size:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineSpiralStep">
<property name="text">
<string>512</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer_8">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="pageVillage">
<layout class="QGridLayout" name="gridLayoutVillage">
<property name="leftMargin">
@ -1669,14 +1812,14 @@ QPushButton:hover {
</customwidget>
</customwidgets>
<tabstops>
<tabstop>comboBoxCat</tabstop>
<tabstop>comboBoxType</tabstop>
<tabstop>comboCat</tabstop>
<tabstop>comboType</tabstop>
<tabstop>spinBox</tabstop>
<tabstop>lineEditX1</tabstop>
<tabstop>lineEditZ1</tabstop>
<tabstop>lineEditX2</tabstop>
<tabstop>lineEditZ2</tabstop>
<tabstop>comboBoxRelative</tabstop>
<tabstop>comboRelative</tabstop>
<tabstop>stackedWidget</tabstop>
</tabstops>
<resources>

View File

@ -52,7 +52,9 @@ ConfigDialog::ConfigDialog(QWidget *parent, Config *config)
int hsc = ui->scrollAreaWidgetContents->sizeHint().height();
int hpa = parent->size().height();
int h = size.height();
h += hsc - hsa + layout()->margin();
int m1, m2;
layout()->getContentsMargins(0, &m1, 0, &m2);
h += hsc - hsa + m1 + m2;
if (h > hpa) h = hpa;
size.setHeight(h);
resize(size);

View File

@ -75,7 +75,7 @@ FormConditions::FormConditions(QWidget *parent)
}
qRegisterMetaType< Condition >("Condition");
qRegisterMetaTypeStreamOperators< Condition >("Condition");
// qRegisterMetaTypeStreamOperators< Condition >("Condition");
}
FormConditions::~FormConditions()
@ -117,10 +117,12 @@ void FormConditions::updateSensitivity()
ui->buttonEdit->setEnabled(false);
}
QVector<Condition> selcond;
int disabled = 0;
for (int i = 0; i < selected.size(); i++)
{
Condition c = qvariant_cast<Condition>(selected[i]->data(Qt::UserRole));
selcond.append(c);
if (c.meta & Condition::DISABLED)
disabled++;
}
@ -131,6 +133,8 @@ void FormConditions::updateSensitivity()
else
ui->buttonDisable->setText(tr("Toggle"));
ui->buttonDisable->setEnabled(!selected.empty());
emit selectionUpdate(selcond);
}
@ -207,7 +211,7 @@ void FormConditions::editCondition(QListWidgetItem *item)
return;
WorldInfo wi;
parent->getSeed(&wi);
ConditionDialog *dialog = new ConditionDialog(this, &parent->config, wi.mc, item, (Condition*)item->data(Qt::UserRole).data());
ConditionDialog *dialog = new ConditionDialog(this, parent->getMapView(), &parent->config, wi, item, (Condition*)item->data(Qt::UserRole).data());
QObject::connect(dialog, SIGNAL(setCond(QListWidgetItem*,Condition,int)), this, SLOT(addItemCondition(QListWidgetItem*,Condition,int)), Qt::QueuedConnection);
dialog->show();
}
@ -266,7 +270,7 @@ void FormConditions::on_buttonAddFilter_clicked()
return;
WorldInfo wi;
parent->getSeed(&wi);
ConditionDialog *dialog = new ConditionDialog(this, &parent->config, wi.mc);
ConditionDialog *dialog = new ConditionDialog(this, parent->getMapView(), &parent->config, wi);
QObject::connect(dialog, SIGNAL(setCond(QListWidgetItem*,Condition,int)), this, SLOT(addItemCondition(QListWidgetItem*,Condition)), Qt::QueuedConnection);
dialog->show();
}

View File

@ -44,6 +44,7 @@ public:
signals:
void changed();
void selectionUpdate(const QVector<Condition>& selected);
public slots:
void on_buttonRemoveAll_clicked();

View File

@ -487,21 +487,21 @@ void FormSearchControl::on_buttonSearchHelp_clicked()
mb.setText(tr(
"<html><head/><body><p>"
"The <b>incremental</b> search checks seeds in numerical order, "
"save for grouping into work items for parallelization. This type "
"of search is best suited for a non-exhaustive search space and "
"with strong biome dependencies. You can restrict this type of "
"search to a value range using the &quot;...&quot; button."
"except for grouping seeds into work items for parallelization. "
"This is the recommended option for general searches. You can "
"restrict this type of search to a value range using the "
"&quot;...&quot; button."
"</p><p>"
"When searching <b>48-bit only</b>, the search is limited to the seed "
"bases and does not yield matching seeds, but rather checks only the "
"parts of the conditions can be determined from the lower 48-bits. "
"Sessions saved from this search are suitable to be used later with "
"the 48-bit generator to look for matching seeds."
"When using <b>48-bit only</b>, the search checks partial seeds and "
"will not test the full conditions. Instead it yields seed bases "
"that may satify the conditions without knowing the upper 16-bit of "
"the seed. A session file saved from this search is suitable to be used "
"later with the 48-bit generator to look for matching seeds."
"</p><p>"
"With <b>48-bit family blocks</b> the search looks for suitable "
"48-bit seeds first and parallelizes the search through the upper "
"16-bits. This search type is best suited for exhaustive searches and "
"those with very restrictive structure requirements."
"16-bits. This search type can be a better match for exhaustive searches "
"and those with very restrictive structure requirements."
"</p><p>"
"Load a <b>seed list from a file</b> to search through an "
"existing set of seeds. The seeds should be in decimal ASCII text, "
@ -585,7 +585,7 @@ void FormSearchControl::searchResult(uint64_t seed)
qbuf.push_back(seed);
if (ui->checkStop->isChecked())
{
onBufferTimeout();
stopSearch();
return;
}

View File

@ -8,6 +8,7 @@
#include <QElapsedTimer>
#include <QAbstractTableModel>
#include <QSortFilterProxyModel>
#include <QFile>
#include <deque>

View File

@ -167,7 +167,7 @@ QPushButton:hover {
</font>
</property>
<property name="toolTip">
<string>Queued progress within search set</string>
<string>Queued progress within the search set</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>

View File

@ -74,7 +74,7 @@ void GotoDialog::keyPressEvent(QKeyEvent *event)
{
QClipboard *clipboard = QGuiApplication::clipboard();
QString s = clipboard->text().trimmed();
QStringList xz = s.split(QRegExp("[, ]+"));
QStringList xz = s.split(QRegularExpression("[, ]+"));
if (xz.count() == 2)
{
ui->lineX->setText(xz[0]);

View File

@ -5,125 +5,96 @@
#include <QApplication>
const char *getLayerOptionText(int mode, int disp)
bool getLayerOptionInfo(LayerOptInfo *info, int mode, int disp, WorldInfo wi)
{
/*
Para 0:
4096 0.952381
1024 0.158730
Para 1:
1024 0.564374
512 0.282187
Para 2:
2048 0.751468
1024 0.375734
512 0.375734
256 0.187867
128 0.093933
64 0.023483
32 0.011742
16 0.005871
8 0.002935
Para 3:
2048 0.716846
1024 0.358423
256 0.089606
128 0.044803
Para 4:
32 0.666667
16 0.333333
8 0.166667
Para 5:
512 0.634921
256 0.634921
128 0.158730
*/
QString txt;
QString tip;
int nptype = -1;
switch (mode)
{
case LOPT_BIOMES:
switch (disp) {
case 0: return "1:1";
case 1: return "1:4";
case 2: return "1:16";
case 3: return "1:64";
case 4: return "1:256";
default: return nullptr;
}
case LOPT_NOISE_T_4:
switch (disp) {
case 0: return "All";
case 1: return "+A[0] 1:4096 x0.952381";
case 2: return "+B[0] 1:4023 x0.952381";
case 3: return "+A[1] 1:1024 x0.158730";
case 4: return "+B[1] 1:1005 x0.158730";
default: return nullptr;
}
case LOPT_NOISE_H_4:
switch (disp) {
case 0: return "All";
case 1: return "+A[0] 1:1024 x0.564374";
case 2: return "+B[0] 1:1005 x0.564374";
case 3: return "+A[1] 1:512 x0.282187";
case 4: return "+B[1] 1:502 x0.282187";
default: return nullptr;
}
case LOPT_NOISE_C_4:
switch (disp) {
case 0: return "All";
case 1: return "+A[0] 1:2048 x0.751468";
case 2: return "+B[0] 1:2011 x0.751468";
case 3: return "+A[1] 1:1024 x0.375734";
case 4: return "+B[1] 1:1005 x0.375734";
case 5: return "+A[2] 1:512 x0.375734";
case 6: return "+B[2] 1:502 x0.375734";
case 7: return "+A[3] 1:256 x0.187867";
case 8: return "+B[3] 1:251 x0.187867";
case 9: return "+A[4] 1:128 x0.093933";
case 10: return "+B[4] 1:125 x0.093933";
case 11: return "+A[5] 1:64 x0.023483";
case 12: return "+B[5] 1:62 x0.023483";
case 13: return "+A[6] 1:32 x0.011742";
case 14: return "+B[6] 1:31 x0.011742";
default: return nullptr;
}
case LOPT_NOISE_E_4:
switch (disp) {
case 0: return "All";
case 1: return "+A[0] 1:2048 x0.716846";
case 2: return "+B[0] 1:2011 x0.716846";
case 3: return "+A[1] 1:1024 x0.358423";
case 4: return "+B[1] 1:1005 x0.358423";
case 5: return "+A[2] 1:256 x0.089606";
case 6: return "+B[2] 1:251 x0.089606";
case 7: return "+A[3] 1:128 x0.044803";
case 8: return "+B[3] 1:125 x0.044803";
default: return nullptr;
}
case LOPT_NOISE_W_4:
switch (disp) {
case 0: return "All";
case 1: return "+A[0] 1:512 x0.634921";
case 2: return "+B[0] 1:502 x0.634921";
case 3: return "+A[1] 1:256 x0.634921";
case 4: return "+B[1] 1:251 x0.634921";
case 5: return "+A[2] 1:128 x0.158730";
case 6: return "+B[2] 1:125 x0.158730";
default: return nullptr;
}
if (disp == 0) txt = "1:1";
if (disp == 1) txt = "1:4";
if (disp == 2) txt = "1:16";
if (disp == 3) txt = "1:64";
if (disp == 4) txt = "1:256";
break;
case LOPT_HEIGHT_4:
switch (disp) {
case 0: return QT_TRANSLATE_NOOP("LayerDialog", "Grayscale");
case 1: return QT_TRANSLATE_NOOP("LayerDialog", "Shaded biome map");
case 2: return QT_TRANSLATE_NOOP("LayerDialog", "Contours on biomes");
case 3: return QT_TRANSLATE_NOOP("LayerDialog", "Shaded with contours");
default: return nullptr;
}
default:
return nullptr;
if (disp == 0) txt = QApplication::translate("LayerDialog", "Grayscale");
if (disp == 1) txt = QApplication::translate("LayerDialog", "Shaded biome map");
if (disp == 2) txt = QApplication::translate("LayerDialog", "Contours on biomes");
if (disp == 3) txt = QApplication::translate("LayerDialog", "Shaded with contours");
break;
case LOPT_NOISE_T_4: nptype = NP_TEMPERATURE; break;
case LOPT_NOISE_H_4: nptype = NP_HUMIDITY; break;
case LOPT_NOISE_C_4: nptype = NP_CONTINENTALNESS; break;
case LOPT_NOISE_E_4: nptype = NP_EROSION; break;
case LOPT_NOISE_W_4: nptype = NP_WEIRDNESS; break;
}
if (nptype != -1 && disp >= 0)
{
BiomeNoise bn;
initBiomeNoise(&bn, wi.mc);
setBiomeSeed(&bn, wi.seed, wi.large);
DoublePerlinNoise *dpn = bn.climate + nptype;
PerlinNoise *oct[2] = { dpn->octA.octaves, dpn->octB.octaves };
int noct = dpn->octA.octcnt;
int idx = noct-1;
int ab = 1;
if (disp > 0)
{
idx = (disp - 1) / 2;
ab = (disp - 1) % 2;
if (idx >= noct)
return false;
}
double ampsum = 0, amptot = 0;
for (int i = 0; i < noct; i++)
{
for (int j = 0; j <= 1; j++)
{
double a = oct[j][i].amplitude;
amptot += a;
if (i < idx || (idx == i && j <= ab))
ampsum += a;
}
}
amptot *= dpn->amplitude;
ampsum *= dpn->amplitude;
double f = 337.0 / 331.0;
PerlinNoise *pn = &oct[ab][idx];
double a = pn->amplitude * dpn->amplitude;
double l = pn->lacunarity * (ab == 0 ? 1.0 : f);
if (disp == 0)
{
txt += QString("%1.. x%2").arg(QChar(0x03A3)).arg(amptot, 0, 'f', 6);
tip += QApplication::translate("LayerDialog", "All octaves");
}
else
{
txt += QString("%1..").arg(QChar(0x03A3));
txt += QString::asprintf("%d%c 1:%-5.0f x%.6f", idx, ab?'B':'A', 1.0/l, a);
tip += QApplication::translate("LayerDialog", "Contribution of the %n most significant octaves out of %1 total.", "", disp).arg(2*noct);
}
tip += "\n" + QApplication::translate("LayerDialog", "Total contribution: %1 = %2%").arg(ampsum).arg(100 * ampsum / amptot, 0, 'f', 1);
tip += "\n" + QApplication::translate("LayerDialog", "Octave amplitude: %1").arg(a);
tip += "\n" + QApplication::translate("LayerDialog", "Octave lacunarity: %1 = 1/%2").arg(l).arg(1.0/l);
}
if (info) {
info->summary = txt;
info->tooltip = tip;
}
return !txt.isEmpty();
}
LayerDialog::LayerDialog(QWidget *parent, int mc)
LayerDialog::LayerDialog(QWidget *parent, WorldInfo wi)
: QDialog(parent)
, ui(new Ui::LayerDialog)
, radio{}
@ -157,18 +128,21 @@ LayerDialog::LayerDialog(QWidget *parent, int mc)
{
if (!combo[i])
continue;
QStringList items;
for (int j = 0; ; j++)
{
const char *item = getLayerOptionText(i, j);
if (!item)
LayerOptInfo info;
if (!getLayerOptionInfo(&info, i, j, wi))
break;
QString s = QApplication::translate("LayerDialog", item).leftJustified(24);
QString s = info.summary.leftJustified(24);
if (j < 9)
s += "\tALT+"+QString::number(j+1);
items.append(s);
combo[i]->addItem(s);
combo[i]->setItemData(combo[i]->count()-1, info.tooltip, Qt::ToolTipRole);
}
combo[i]->addItems(items);
connect(combo[i], QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int){
this->onComboChange(combo[i]);
});
onComboChange(combo[i]);
}
QFont fmono;
@ -182,17 +156,17 @@ LayerDialog::LayerDialog(QWidget *parent, int mc)
combo[i]->setFont(fmono);
if (i >= LOPT_NOISE_T_4 && i <= LOPT_NOISE_W_4)
{
radio[i]->setEnabled(mc > MC_1_17);
radio[i]->setEnabled(wi.mc > MC_1_17);
if (combo[i])
combo[i]->setEnabled(mc > MC_1_17);
combo[i]->setEnabled(wi.mc > MC_1_17);
}
if (i == LOPT_RIVER_4 || i == LOPT_OCEAN_256)
{
radio[i]->setEnabled(mc > MC_1_12 && mc <= MC_1_17);
radio[i]->setEnabled(wi.mc > MC_1_12 && wi.mc <= MC_1_17);
}
if (i == LOPT_NOOCEAN_1 || i == LOPT_BETA_T_1 || i == LOPT_BETA_H_1)
{
radio[i]->setEnabled(mc <= MC_B1_7);
radio[i]->setEnabled(wi.mc <= MC_B1_7);
}
}
}
@ -235,6 +209,11 @@ void LayerDialog::onRadioChange()
}
}
void LayerDialog::onComboChange(QComboBox *combo)
{
combo->setToolTip(combo->currentData(Qt::ToolTipRole).toString());
}
void LayerDialog::on_buttonBox_clicked(QAbstractButton *button)
{
QDialogButtonBox::StandardButton b = ui->buttonBox->standardButton(button);

View File

@ -11,14 +11,20 @@ namespace Ui {
class LayerDialog;
}
const char *getLayerOptionText(int mode, int disp);
struct LayerOptInfo
{
QString summary;
QString tooltip;
};
bool getLayerOptionInfo(LayerOptInfo *info, int mode, int disp, WorldInfo wi);
class LayerDialog : public QDialog
{
Q_OBJECT
public:
explicit LayerDialog(QWidget *parent, int mc);
explicit LayerDialog(QWidget *parent, WorldInfo mc);
~LayerDialog();
void setLayerOptions(LayerOpt lopts);
@ -29,6 +35,7 @@ signals:
public slots:
void onRadioChange();
void onComboChange(QComboBox *combo);
private slots:
void on_buttonBox_clicked(QAbstractButton *button);

View File

@ -10,6 +10,7 @@
#include "exportdialog.h"
#include "layerdialog.h"
#include "tabtriggers.h"
#include "tablocations.h"
#include "tabbiomes.h"
#include "tabstructures.h"
#include "message.h"
@ -52,7 +53,8 @@ MainWindow::MainWindow(QString sessionpath, QString resultspath, QWidget *parent
, sessionpath(sessionpath)
, prevdir(".")
, autosaveTimer()
, prevtab(-1)
, tabidx(-1)
, tabsearch(-1)
, dimactions{}
, dimgroup()
{
@ -86,7 +88,8 @@ MainWindow::MainWindow(QString sessionpath, QString resultspath, QWidget *parent
ui->menuHistory->clear();
ui->tabContainer->addTab(new TabTriggers(this), tr("Triggers"));
ui->tabContainerSearch->addTab(new TabTriggers(this), tr("Triggers"));
ui->tabContainerSearch->addTab(new TabLocations(this), tr("Locations"));
ui->tabContainer->addTab(new TabBiomes(this), tr("Biomes"));
ui->tabContainer->addTab(new TabStructures(this), tr("Structures"));
@ -185,7 +188,8 @@ MainWindow::MainWindow(QString sessionpath, QString resultspath, QWidget *parent
saction[D_GRID]->setChecked(true);
ui->splitterMap->setSizes(QList<int>({6500, 10000}));
ui->splitterSearch->setSizes(QList<int>({1000, 1000, 2000}));
ui->splitterSearch->setSizes(QList<int>({1000, 3000}));
ui->splitterSeeds->setSizes(QList<int>({500, 2500}));
qRegisterMetaType< int64_t >("int64_t");
qRegisterMetaType< uint64_t >("uint64_t");
@ -202,6 +206,7 @@ MainWindow::MainWindow(QString sessionpath, QString resultspath, QWidget *parent
ui->collapseConstraints->init(tr("Conditions"), formCond, false);
connect(formCond, &FormConditions::changed, this, &MainWindow::onConditionsChanged);
connect(formCond, &FormConditions::selectionUpdate, this, &MainWindow::onConditionsSelect);
ui->collapseConstraints->setInfo(
tr("Help: Conditions"),
tr(
@ -304,7 +309,7 @@ bool MainWindow::loadTranslation(QString lang)
static QTranslator qt_translator;
if (!rc_translator.load(lang, ":/lang"))
return false;
QLocale::setDefault(lang);
QLocale::setDefault(QLocale(lang));
QString qt_locale = "qtbase_" + lang;
QString qt_trpath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
if (qt_translator.load(qt_locale, qt_trpath))
@ -432,8 +437,9 @@ bool MainWindow::setSeed(WorldInfo wi, int dim)
ui->seedEdit->setEnabled(true);
ui->comboY->setEnabled(true);
ISaveTab *tab = dynamic_cast<ISaveTab*>(ui->tabContainer->currentWidget());
if (tab)
if (ISaveTab *tab = dynamic_cast<ISaveTab*>(ui->tabContainer->currentWidget()))
tab->refresh();
if (ISaveTab *tab = dynamic_cast<ISaveTab*>(ui->tabContainerSearch->currentWidget()))
tab->refresh();
return true;
}
@ -466,6 +472,7 @@ void MainWindow::saveSettings()
g_extgen.save(settings);
on_tabContainer_currentChanged(-1);
on_tabContainerSearch_currentChanged(-1);
WorldInfo wi;
getSeed(&wi, false);
@ -497,7 +504,7 @@ void MainWindow::loadSettings()
showMaximized();
} else {
resize(settings.value("mainwindow/size", size()).toSize());
move(settings.value("mainwindow/pos", pos()).toPoint());
//move(settings.value("mainwindow/pos", pos()).toPoint());
}
prevdir = settings.value("mainwindow/prevdir", prevdir).toString();
@ -635,7 +642,7 @@ void MainWindow::setDockable(bool dockable)
// and avoid a warning about negative size widget
QWidget *title = new QWidget(this);
QHBoxLayout *l = new QHBoxLayout(title);
l->setMargin(0);
l->setContentsMargins(0, 0, 0, 0);
title->setLayout(l);
dock->setTitleBarWidget(title);
dock->setFloating(false);
@ -885,7 +892,7 @@ void MainWindow::on_actionLayerDisplay_triggered()
{
WorldInfo wi;
getSeed(&wi, false);
LayerDialog *dialog = new LayerDialog(this, wi.mc);
LayerDialog *dialog = new LayerDialog(this, wi);
dialog->setLayerOptions(lopt);
connect(dialog, &LayerDialog::apply, [=](){
lopt = dialog->getLayerOptions();
@ -895,14 +902,24 @@ void MainWindow::on_actionLayerDisplay_triggered()
dialog->show();
}
void MainWindow::on_tabContainer_currentChanged(int index)
static int tab_switch(QTabWidget *tabs, int idxprev, int idxnext)
{
QSettings settings(APP_STRING, APP_STRING);
ISaveTab *tabold = dynamic_cast<ISaveTab*>(ui->tabContainer->widget(prevtab));
ISaveTab *tabnew = dynamic_cast<ISaveTab*>(ui->tabContainer->widget(index));
ISaveTab *tabold = dynamic_cast<ISaveTab*>(tabs->widget(idxprev));
ISaveTab *tabnew = dynamic_cast<ISaveTab*>(tabs->widget(idxnext));
if (tabold) tabold->save(settings);
if (tabnew) tabnew->load(settings);
prevtab = index;
return idxnext;
}
void MainWindow::on_tabContainer_currentChanged(int index)
{
tabidx = tab_switch(ui->tabContainer, tabidx, index);
}
void MainWindow::on_tabContainerSearch_currentChanged(int index)
{
tabsearch = tab_switch(ui->tabContainerSearch, tabsearch, index);
}
void MainWindow::on_actionSearch_seed_list_triggered()
@ -946,16 +963,16 @@ void MainWindow::onActionMapToggled(int sopt, bool show)
void MainWindow::onActionBiomeLayerSelect(int mode, int disp)
{
WorldInfo wi;
getSeed(&wi, false);
lopt.mode = mode;
if (disp >= 0)
{
if (!getLayerOptionText(mode, disp))
if (!getLayerOptionInfo(nullptr, mode, disp, wi))
return; // unsupported display mode
lopt.disp[mode] = disp;
}
lopt.mode = mode;
WorldInfo wi;
if (getSeed(&wi, false))
setSeed(wi, DIM_UNDEF);
setSeed(wi, DIM_UNDEF);
}
void MainWindow::onConditionsChanged()
@ -964,6 +981,37 @@ void MainWindow::onConditionsChanged()
formGen48->updateAutoConditions(conds);
}
void MainWindow::onConditionsSelect(const QVector<Condition>& selection)
{
std::vector<Shape> shapes;
for (const Condition& c : selection)
{
if (c.meta & Condition::DISABLED)
continue;
if (c.relative)
continue;
const FilterInfo& ft = g_filterinfo.list[c.type];
Shape s;
s.dim = ft.dim;
if (c.rmax)
{
s.type = Shape::CIRCLE;
s.p1 = s.p2 = Pos{0,0};
s.r = c.rmax - 1;
}
else
{
s.type = Shape::RECT;
s.p1 = Pos{c.x1, c.z1};
s.p2 = Pos{c.x2+1, c.z2+1};
s.r = 0;
}
shapes.push_back(s);
}
getMapView()->setShapes(shapes);
}
void MainWindow::onGen48Changed()
{
formGen48->updateCount();

View File

@ -103,6 +103,7 @@ private slots:
void on_actionLayerDisplay_triggered();
void on_tabContainer_currentChanged(int index);
void on_tabContainerSearch_currentChanged(int index);
void on_actionSearch_seed_list_triggered();
void on_actionSearch_full_seed_space_triggered();
@ -113,6 +114,7 @@ private slots:
void onActionHistory(QAction *act);
void onActionBiomeLayerSelect(int lopt, int disp = -1);
void onConditionsChanged();
void onConditionsSelect(const QVector<Condition>& selection);
void onGen48Changed();
void onSelectedSeedChanged(uint64_t seed);
void onSearchStatusChanged(bool running);
@ -136,7 +138,8 @@ public:
QString sessionpath;
QString prevdir;
QTimer autosaveTimer;
int prevtab;
int tabidx;
int tabsearch;
QVector<QAction*> laction;
QVector<QAction*> saction;

View File

@ -211,6 +211,11 @@
</item>
<item>
<widget class="QTabWidget" name="tabContainer">
<property name="styleSheet">
<string notr="true">QToolButton {
background-color: transparent;
}</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
@ -224,120 +229,68 @@
<attribute name="title">
<string>Search</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QScrollArea" name="scrollArea">
<property name="minimumSize">
<size>
<width>540</width>
<height>0</height>
</size>
<widget class="QSplitter" name="splitterSearch">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="styleSheet">
<string notr="true">QAbstractScrollArea#scrollArea {
border: 0px none;
}
QToolButton {
background-color: transparent;
}</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<widget class="Collapsible" name="collapseConstraints" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>440</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_2">
</widget>
<widget class="QWidget" name="gridLayoutWidget">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
<number>18</number>
</property>
<item row="0" column="0">
<widget class="QSplitter" name="splitterSearch">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<widget class="QTabWidget" name="tabContainerSearch">
<property name="currentIndex">
<number>0</number>
</property>
<property name="styleSheet">
<string notr="true">
QSplitter {
background-color: transparent;
}</string>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="Collapsible" name="collapseConstraints" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="Collapsible" name="collapseGen48" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="Collapsible" name="collapseControl" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<widget class="QWidget" name="tabSeeds">
<attribute name="title">
<string>Seeds</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QSplitter" name="splitterSeeds">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="Collapsible" name="collapseGen48" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="Collapsible" name="collapseControl" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>

View File

@ -59,7 +59,7 @@ MapView::MapView(QWidget *parent)
setFont(fmono);
QPalette pal = palette();
pal.setColor(QPalette::Background, Qt::black);
pal.setColor(QPalette::Dark, Qt::black);
setAutoFillBackground(true);
setPalette(pal);
@ -189,6 +189,13 @@ void MapView::setConfig(const Config& c)
update(2);
}
void MapView::setShapes(const std::vector<Shape>& s)
{
shapes = s;
settingsToWorld();
update(1);
}
void MapView::refreshBiomeColors()
{
if (world)
@ -207,6 +214,7 @@ void MapView::settingsToWorld()
world->memlimit = (uint64_t) config.mapCacheSize * 1024 * 1024;
world->threadlimit = config.mapThreads;
world->lopt = lopt;
world->shapes = shapes;
}
static qreal smoothstep(qreal x)
@ -304,6 +312,27 @@ qreal MapView::getZ()
return fz;
}
static qreal clampimax(qreal x, bool *ok = nullptr)
{
const double imax = INT_MAX - 1024.0;
if (x < -imax) x = -imax;
if (x > +imax) x = +imax;
if (ok) *ok = (x > -imax && x < +imax);
return x;
}
void MapView::getVisible(int *x0, int *z0, int *x1, int *z1)
{
qreal x = getX();
qreal z = getZ();
qreal uiw = width() / blocks2pix;
qreal uih = height() / blocks2pix;
if (x0) *x0 = (int) clampimax( floor(x - uiw/2) );
if (z0) *z0 = (int) clampimax( floor(z - uih/2) );
if (x1) *x1 = (int) clampimax( ceil(x + uiw/2) );
if (z1) *z1 = (int) clampimax( ceil(z + uih/2) );
}
void MapView::update(int cnt)
{
updatecounter = cnt;
@ -435,19 +464,12 @@ void MapView::onGoto()
dialog->show();
}
static bool clampabs(qreal *x, qreal m)
{
if (*x < -m) { *x = -m; return true; }
if (*x > +m) { *x = +m; return true; }
return false;
}
void MapView::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::HighQualityAntialiasing);
//painter.setRenderHint(QPainter::HighQualityAntialiasing);
qreal fx = getX();
qreal fz = getZ();
@ -458,8 +480,11 @@ void MapView::paintEvent(QPaintEvent *)
focusz = z_dst;
blocks2pix = 1.0 / s_dst;
}
if (clampabs(&fx, INT_MAX-1024)) focusx = fx;
if (clampabs(&fz, INT_MAX-1024)) focusz = fz;
bool ok;
fx = clampimax(fx, &ok);
if (!ok) focusx = fx;
fz = clampimax(fz, &ok);
if (!ok) focusz = fz;
if (world)
{
@ -468,9 +493,7 @@ void MapView::paintEvent(QPaintEvent *)
QPoint cur = mapFromGlobal(QCursor::pos());
qreal bx = (cur.x() - width()/2.0) / blocks2pix + fx;
qreal bz = (cur.y() - height()/2.0) / blocks2pix + fz;
clampabs(&bx, INT_MAX-1024);
clampabs(&bz, INT_MAX-1024);
Pos p = {(int)bx, (int)bz};
Pos p = {(int)clampimax(bx), (int)clampimax(bz)};
overlay->pos = p;
overlay->bname = world->getBiomeName(p);

View File

@ -35,6 +35,7 @@ public:
qreal getX();
qreal getZ();
qreal getScale() const { return 1.0 / blocks2pix; }
void getVisible(int *x0, int *z0, int *x1, int *z1);
void deleteWorld();
void refresh();
@ -53,6 +54,7 @@ public:
bool getShow(int stype);
void setShow(int stype, bool v);
void setConfig(const Config& config);
void setShapes(const std::vector<Shape>& shapes);
void refreshBiomeColors();
void timeout();
@ -110,6 +112,8 @@ private:
bool measure;
int updatecounter;
std::vector<Shape> shapes;
bool sshow[D_STRUCT_NUM];
LayerOpt lopt;
Config config;

View File

@ -207,7 +207,7 @@ LabeledRange::LabeledRange(QWidget *parent, int vmin, int vmax)
l->addWidget(minlabel);
l->addWidget(slider);
l->addWidget(maxlabel);
l->setMargin(0);
l->setContentsMargins(0, 0, 0, 0);
setLayout(l);
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(rangeChanged(void)));

View File

@ -72,7 +72,7 @@ void getScripts(QMap<uint64_t, QString>& scripts)
QDirIterator it(dir, QDirIterator::NoIteratorFlags);
while (it.hasNext())
{
QFileInfo f = it.next();
QFileInfo f = QFileInfo(it.next());
if (f.suffix() != "lua")
continue;
uint64_t hash = getScriptHash(f);
@ -436,19 +436,32 @@ BlockRule *LuaHighlighter::nextBlockRule(const QString& text, int *pos, int *nex
{
BlockRule *rule = nullptr;
int min = INT_MAX;
int end = 0;
for (int i = 0, n = blockrules.size(); i < n; i++)
{
#if 1
QRegularExpressionMatch m = blockrules[i].start.match(text, *pos);
if (m.hasMatch() && m.capturedStart() < min)
{
rule = &blockrules[i];
min = m.capturedStart();
end = m.capturedEnd();
}
}
#else
int s = blockrules[i].start.indexIn(text, *pos);
if (s >= 0 && s < min)
{
rule = &blockrules[i];
min = s;
end = s + rule->start.matchedLength();
}
}
#endif
if (rule)
{
*pos = min;
*next = min + rule->start.matchedLength();
*next = end;
}
return rule;
}
@ -467,6 +480,21 @@ void LuaHighlighter::highlightBlock(const QString& text)
while (rule)
{
#if 1
QRegularExpressionMatch m = rule->end.match(text, match);
if (m.hasMatch())
{
markFormated(&line, start, line.length() - start, rule->format);
break;
}
else
{
int end = m.capturedEnd();
markFormated(&line, start, end - start, rule->format);
start = end;
rule = nextBlockRule(line, &start, &match);
}
#else
int end = rule->end.indexIn(text, match);
if (end == -1)
{
@ -480,6 +508,7 @@ void LuaHighlighter::highlightBlock(const QString& text)
start = end;
rule = nextBlockRule(line, &start, &match);
}
#endif
}
if (rule)
setCurrentBlockState(rule - &blockrules[0]);
@ -489,6 +518,14 @@ void LuaHighlighter::highlightBlock(const QString& text)
for (const Rule &rule : qAsConst(rules))
{
const QString *l = rule.overlay ? &text : &line;
#if 1
QRegularExpressionMatch m = rule.pattern.match(*l);
while (m.hasMatch())
{
setFormat(m.capturedStart(), m.capturedLength(), rule.format);
m = rule.pattern.match(*l, m.capturedEnd());
}
#else
QRegExp expression(rule.pattern);
int index = expression.indexIn(*l);
while (index >= 0)
@ -497,6 +534,7 @@ void LuaHighlighter::highlightBlock(const QString& text)
setFormat(index, length, rule.format);
index = expression.indexIn(*l, index + length);
}
#endif
}
}
@ -633,7 +671,7 @@ void ScriptEditor::keyPressEvent(QKeyEvent *event)
{
const QString text = document()->toPlainText();
const QChar linebreak = QChar(0x2029);
QString ws = linebreak + QStringRef(&text, start, end-start).toString();
QString ws = linebreak + text.mid(start, end-start);
cursor.beginEditBlock();
cursor.insertText(ws);
cursor.endEditBlock();

View File

@ -8,6 +8,7 @@
#include <QPlainTextEdit>
#include <QMutex>
#include <QSyntaxHighlighter>
#include <QRegularExpression>
#include "cubiomes/finders.h"
@ -60,7 +61,7 @@ int runCheckScript(
struct Rule
{
QRegExp pattern;
QRegularExpression pattern;
QTextCharFormat format;
bool overlay;
Rule() : pattern(),format(),overlay() {}
@ -69,7 +70,7 @@ struct Rule
};
struct BlockRule
{
QRegExp start, end;
QRegularExpression start, end;
QTextCharFormat format;
BlockRule() : start(), end(), format() {}
BlockRule(const QString& s, const QString& e, const QTextCharFormat& f)

View File

@ -34,7 +34,7 @@ QString Condition::summary(bool aligntab) const
}
QString cnts;
if (ft.count)
if (ft.branch == FilterInfo::BR_CLUST)
cnts += MULTIPLY_CHAR + QString::number(count);
if (skipref)
cnts += "*";
@ -73,10 +73,10 @@ QString Condition::summary(bool aligntab) const
}
else
{
if (ft.coord)
s += QString::asprintf("(%d,%d)", x1*ft.step, z1*ft.step);
if (ft.area)
s += QString::asprintf(",(%d,%d)", (x2+1)*ft.step-1, (z2+1)*ft.step-1);
if (ft.loc & FilterInfo::LOC_1)
s += QString::asprintf("(%d,%d)", x1, z1);
if (ft.loc & FilterInfo::LOC_2)
s += QString::asprintf(",(%d,%d)", x2, z2);
}
return s;
}
@ -95,15 +95,13 @@ bool Condition::versionUpgrade()
memset(pad1, 0, sizeof(pad1));
hash = 0;
memset(deps, 0, sizeof(deps));
memset(pad2, 0, sizeof(pad2));
biomeId = biomeSize = tol = minmax = para = octave = 0;
varflags = varbiome = varstart = 0;
biomeId = biomeSize = tol = minmax = para = octave = step = 0;
}
else if (version == VER_2_3_0)
if (version < VER_2_4_0)
{
varflags = varbiome = varstart = 0;
}
else if (version == VER_2_4_0)
if (version < VER_3_4_0)
{
if (type == F_CLIMATE_MINMAX)
{
@ -126,6 +124,28 @@ bool Condition::versionUpgrade()
}
}
}
if (version < VER_4_0_0)
{
const FilterInfo& ft = g_filterinfo.list[type];
if (ft.grid > 1)
{
x1 = x1 * ft.grid;
z1 = z1 * ft.grid;
x2 = (x2+1) * ft.grid - 1;
z2 = (z2+1) * ft.grid - 1;
}
switch (type)
{
case F_SPIRAL: step = 1; break;
case F_SPIRAL_4: step = 4; type = F_SPIRAL; break;
case F_SPIRAL_16: step = 16; type = F_SPIRAL; break;
case F_SPIRAL_64: step = 64; type = F_SPIRAL; break;
case F_SPIRAL_256: step = 256; type = F_SPIRAL; break;
case F_SPIRAL_512: step = 512; type = F_SPIRAL; break;
case F_SPIRAL_1024: step = 1024; type = F_SPIRAL; break;
}
}
version = VER_CURRENT;
return true;
}
@ -312,66 +332,96 @@ int testTreeAt(
ConditionTree *tree = env->condtree;
Condition& c = tree->condvec[node];
const std::vector<char>& branches = tree->references[c.save];
int st;
int st, br;
int rx1, rz1, rx2, rz2;
int sref;
Pos pos;
Pos inst[MAX_INSTANCES];
const FilterInfo *finfo;
switch (c.type)
{
case F_SPIRAL_1: sref = 0; goto L_ref_pow2;
case F_SPIRAL_4: sref = 2; goto L_ref_pow2;
case F_SPIRAL_16: sref = 4; goto L_ref_pow2;
case F_SPIRAL_64: sref = 6; goto L_ref_pow2;
case F_SPIRAL_256: sref = 8; goto L_ref_pow2;
case F_SPIRAL_512: sref = 9; goto L_ref_pow2;
case F_SPIRAL_1024: sref = 10; goto L_ref_pow2;
L_ref_pow2:
rx1 = ((c.x1 << sref) + at.x) >> sref;
rz1 = ((c.z1 << sref) + at.z) >> sref;
rx2 = ((c.x2 << sref) + at.x) >> sref;
rz2 = ((c.z2 << sref) + at.z) >> sref;
case F_SPIRAL:
st = COND_FAILED;
{ // run a spiral iterator over the rectangle
int x = (rx1 + rx2) >> 1;
int z = (rz1 + rz2) >> 1;
int step = c.step ? c.step : 512;
int rmax, x1, z1, x2, z2;
if (c.rmax > 0)
{
rmax = c.rmax - 1;
x1 = at.x - rmax;
z1 = at.z - rmax;
x2 = at.x + rmax;
z2 = at.z + rmax;
rmax = rmax * rmax + 1;
}
else
{
rmax = 0;
x1 = c.x1 + at.x;
z1 = c.z1 + at.z;
x2 = c.x2 + at.x;
z2 = c.z2 + at.z;
}
rx1 = floordiv(x1, step);
rz1 = floordiv(z1, step);
rx2 = floordiv(x2, step);
rz2 = floordiv(z2, step);
int rx = (rx1 + rx2) >> 1;
int rz = (rz1 + rz2) >> 1;
int i = 0, dl = 1;
int dx = 1, dz = 0;
while (true)
{
bool inx = (x >= rx1 && x <= rx2);
bool inz = (z >= rz1 && z <= rz2);
bool inx = (rx >= rx1 && rx <= rx2);
bool inz = (rz >= rz1 && rz <= rz2);
if (!inx && !inz)
break;
if (inx && inz)
{
pos.x = (x << sref);
pos.z = (z << sref);
// children are combined via AND
int sta = COND_OK;
for (int b : branches)
pos.x = rx * step;
pos.z = rz * step;
bool inr = true;
if (rmax)
{
int stb = testTreeAt(pos, env, pass, abort, path, b);
if (*abort)
return COND_FAILED;
if (stb < sta)
sta = stb;
if (sta == COND_FAILED)
break;
int dx = pos.x - at.x;
int dz = pos.z - at.z;
int64_t rsq = dx*(int64_t)dx + dz*(int64_t)dz;
inr = (rsq < rmax);
}
else if (pos.x < x1 || pos.x > x2 || pos.z < z1 || pos.z > z2)
{
inr = false;
}
if (inr)
{
// children are combined via AND
int sta = COND_OK;
for (int b : branches)
{
int stb = testTreeAt(pos, env, pass, abort, path, b);
if (*abort)
return COND_FAILED;
if (stb < sta)
sta = stb;
if (sta == COND_FAILED)
break;
}
if (sta == COND_MAYBE_POS_VALID )
sta = COND_MAYBE_POS_INVAL; // position moves => invalidate
if (sta > st)
st = sta;
if (path && st >= COND_MAYBE_POS_VALID)
path[c.save] = pos;
if (st == COND_OK)
return COND_OK;
}
if (sta == COND_MAYBE_POS_VALID )
sta = COND_MAYBE_POS_INVAL; // position moves => invalidate
if (sta > st)
st = sta;
if (path && st >= COND_MAYBE_POS_VALID)
path[c.save] = pos;
if (st == COND_OK)
return COND_OK;
}
x += dx;
z += dz;
rx += dx;
rz += dz;
if (++i == dl)
{
i = 0;
@ -412,7 +462,7 @@ int testTreeAt(
return st;
case F_LOGIC_OR:
case F_LOGIC_OR: //qDebug() << at.x << at.z; return COND_FAILED;
if (branches.empty())
{
if (path)
@ -499,18 +549,48 @@ int testTreeAt(
{
if (icnt == 1)
path[c.save] = *inst;
else if (icnt > 1 && st == COND_OK)
path[c.save] = *inst;
else
path[c.save].x = path[c.save].z = -1;
}
return st;
}
finfo = g_filterinfo.list + c.type;
if (c.count == 1 && (finfo->count || finfo->cat == CAT_QUAD))
{ // condition has exactly one required instance so we can check each
// of the found instances individually, i.e. this branch splits the
// instances into independent subbranches (combined via OR)
// quad conditions are also processed here since we want to
// examine all instances without support for averaging
br = g_filterinfo.list[c.type].branch;
if (br == FilterInfo::BR_NONE || (br == FilterInfo::BR_CLUST && c.count != 1))
{ // this condition cannot branch, position of multiple instances
// will be averaged to a center point
if (c.type == 0)
{ // this is the root condition
st = COND_OK;
pos = at;
}
else
{
st = testCondAt(at, env, pass, abort, inst, NULL, &c);
if (st == COND_FAILED || st == COND_MAYBE_POS_INVAL)
return st;
pos = inst[0]; // center point of instances
}
for (char b : branches)
{
if (st == COND_FAILED)
break;
int sta = testTreeAt(pos, env, pass, abort, path, b);
if (*abort)
return COND_FAILED;
if (sta < st)
st = sta;
}
if (path && st >= COND_MAYBE_POS_VALID)
path[c.save] = pos;
return st;
}
else
{ // check each instance individually, splitting the instances into
// independent subbranches that are combined via OR
int icnt = MAX_INSTANCES;
st = testCondAt(at, env, pass, abort, inst, &icnt, &c);
if (st == COND_FAILED || st == COND_MAYBE_POS_INVAL)
@ -548,35 +628,6 @@ int testTreeAt(
path[c.save] = inst[iok];
return st;
}
else
{ // this condition cannot branch, position of multiple instances
// will be averaged to a center point
if (c.type == 0)
{ // this is the root condition
st = COND_OK;
pos = at;
}
else
{
st = testCondAt(at, env, pass, abort, inst, NULL, &c);
if (st == COND_FAILED || st == COND_MAYBE_POS_INVAL)
return st;
pos = inst[0]; // center point of instances
}
for (char b : branches)
{
if (st == COND_FAILED)
break;
int sta = testTreeAt(pos, env, pass, abort, path, b);
if (*abort)
return COND_FAILED;
if (sta < st)
st = sta;
}
if (path && st >= COND_MAYBE_POS_VALID)
path[c.save] = pos;
return st;
}
}
}
@ -895,6 +946,59 @@ static int f_track_minmax(void *data, int x, int z, double p)
return 0;
}
struct sample_boime_t
{
Condition *cond;
Pos at;
int rmaxsq;
int n;
int64_t xsum;
int64_t zsum;
Pos *cent;
int *imax;
std::atomic_bool *stop;
};
static int f_biome_sampler(Generator *g, int scale, int x, int y, int z, void *data)
{
sample_boime_t *info = (sample_boime_t*) data;
if (info->stop && *info->stop)
return -2;
if (info->rmaxsq)
{
int dx = x - info->at.x;
int dz = z - info->at.z;
int64_t rsq = dx*(int64_t)dx + dz*(int64_t)dz;
if (rsq >= info->rmaxsq)
return -1;
}
int id = getBiomeAt(g, scale, x, y, z);
uint64_t incl = 0, excl = 0;
if (id < 128) {
incl = info->cond->biomeToFind & (1ULL << id);
excl = info->cond->biomeToExcl & (1ULL << id);
} else {
incl = info->cond->biomeToFindM & (1ULL << (id-128));
excl = info->cond->biomeToExclM & (1ULL << (id-128));
}
if (incl != 0)
{
if (info->imax && info->n < *info->imax)
info->cent[info->n] = Pos{x, z};
info->xsum += x;
info->zsum += z;
info->n++;
return 1;
}
if (excl != 0)
{
return 0;
}
return 0;
}
/* Tests if a condition is satisfied with 'at' as origin for a search pass.
* If sufficiently satisfied (check return value) then:
* when 'imax' is NULL, the center position is written to 'cent[0]'
@ -933,9 +1037,26 @@ testCondAt(
return COND_FAILED;
}
if (cond->rmax > 0)
{
rmax = cond->rmax - 1;
x1 = at.x - rmax;
z1 = at.z - rmax;
x2 = at.x + rmax;
z2 = at.z + rmax;
}
else
{
rmax = 0;
x1 = cond->x1 + at.x;
z1 = cond->z1 + at.z;
x2 = cond->x2 + at.x;
z2 = cond->z2 + at.z;
}
switch (cond->type)
{
case F_SPIRAL_1:
case F_SPIRAL:
case F_SPIRAL_4:
case F_SPIRAL_16:
case F_SPIRAL_64:
@ -968,10 +1089,10 @@ testCondAt(
n = sizeof(low20QuadHutBarely) / sizeof(uint64_t);
L_qh_any:
rx1 = ((cond->x1 << 9) + at.x) >> 9;
rz1 = ((cond->z1 << 9) + at.z) >> 9;
rx2 = ((cond->x2 << 9) + at.x) >> 9;
rz2 = ((cond->z2 << 9) + at.z) >> 9;
rx1 = x1 >> 9;
rz1 = z1 >> 9;
rx2 = x2 >> 9;
rz2 = z2 >> 9;
n = scanForQuads(
sconf, 128, (env->seed) & MASK48, seeds, n, 20, sconf.salt,
@ -1009,10 +1130,10 @@ L_qh_any:
case F_QM_90: qual = 58*58*4 * 90 / 100;
L_qm_any:
rx1 = ((cond->x1 << 9) + at.x) >> 9;
rz1 = ((cond->z1 << 9) + at.z) >> 9;
rx2 = ((cond->x2 << 9) + at.x) >> 9;
rz2 = ((cond->z2 << 9) + at.z) >> 9;
rx1 = x1 >> 9;
rz1 = z1 >> 9;
rx2 = x2 >> 9;
rz2 = z2 >> 9;
// we don't really need to check for more than one instance here
n = scanForQuads(
sconf, 160, (env->seed) & MASK48, g_qm_90,
@ -1068,23 +1189,6 @@ L_qm_any:
case F_ENDCITY:
case F_GATEWAY:
if (cond->rmax > 0)
{
rmax = (cond->rmax-1) * (cond->rmax-1) + 1;
x1 = at.x - cond->rmax;
z1 = at.z - cond->rmax;
x2 = at.x + cond->rmax;
z2 = at.z + cond->rmax;
}
else
{
rmax = 0;
x1 = cond->x1 + at.x;
z1 = cond->z1 + at.z;
x2 = cond->x2 + at.x;
z2 = cond->z2 + at.z;
}
if (sconf.regionSize == 32)
{
rx1 = x1 >> 9;
@ -1239,41 +1343,12 @@ L_qm_any:
case F_MINESHAFT:
if (cond->rmax > 0)
{
rmax = (cond->rmax-1) * (cond->rmax-1) + 1;
x1 = at.x - cond->rmax;
z1 = at.z - cond->rmax;
x2 = at.x + cond->rmax;
z2 = at.z + cond->rmax;
}
else
{
rmax = 0;
x1 = cond->x1 + at.x;
z1 = cond->z1 + at.z;
x2 = cond->x2 + at.x;
z2 = cond->z2 + at.z;
}
rx1 = x1 >> 4;
rz1 = z1 >> 4;
rx2 = x2 >> 4;
rz2 = z2 >> 4;
if (cond->count <= 0)
{ // exclusion
icnt = getMineshafts(env->mc, env->seed, rx1, rz1, rx2, rz2, cent, 1);
if (icnt == 1 && cond->skipref && cent->x == at.x && cent->z == at.z)
icnt = 0;
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (icnt == 0)
{
if (imax) *imax = 1;
return COND_OK;
}
}
else if (imax)
if (imax && cond->count > 0)
{ // just check there are at least *inst (== cond->count) instances
*imax = icnt =
getMineshafts(env->mc, env->seed, rx1, rz1, rx2, rz2, cent, *imax);
@ -1328,7 +1403,17 @@ L_qm_any:
zt += p[i].z;
j++;
}
if (j >= cond->count)
if (cond->count <= 0)
{
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (j == 0)
{
if (imax) *imax = 1;
return COND_OK;
}
}
else if (j >= cond->count)
{
cent->x = xt / j;
cent->z = zt / j;
@ -1344,22 +1429,6 @@ L_qm_any:
if (pass != PASS_FULL_64)
return COND_MAYBE_POS_INVAL;
if (cond->rmax > 0)
{
rmax = (cond->rmax-1) * (cond->rmax-1) + 1;
x1 = at.x - cond->rmax;
z1 = at.z - cond->rmax;
x2 = at.x + cond->rmax;
z2 = at.z + cond->rmax;
}
else
{
rmax = 0;
x1 = cond->x1 + at.x;
z1 = cond->z1 + at.z;
x2 = cond->x2 + at.x;
z2 = cond->z2 + at.z;
}
if (*abort) return COND_FAILED;
env->init4Dim(DIM_OVERWORLD);
pc = getSpawn(&env->g);
@ -1398,10 +1467,6 @@ L_qm_any:
}
else
{
x1 = cond->x1 + at.x;
z1 = cond->z1 + at.z;
x2 = cond->x2 + at.x;
z2 = cond->z2 + at.z;
if (pc.x < x1 || pc.x > x2 || pc.z < z1 || pc.z > z2)
return COND_FAILED;
}
@ -1564,10 +1629,10 @@ L_qm_any:
case F_SLIME:
rx1 = ((cond->x1 << 4) + at.x) >> 4;
rz1 = ((cond->z1 << 4) + at.z) >> 4;
rx2 = ((cond->x2 << 4) + at.x) >> 4;
rz2 = ((cond->z2 << 4) + at.z) >> 4;
rx1 = x1 >> 4;
rz1 = z1 >> 4;
rx2 = x2 >> 4;
rz2 = z2 >> 4;
icnt = 0;
xt = zt = 0;
@ -1602,8 +1667,8 @@ L_qm_any:
}
if (cond->count == 0)
{ // exclusion filter
cent->x = (rx1 + rx2) << 3;
cent->z = (rz1 + rz2) << 3;
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (imax) *imax = 1;
return COND_OK;
}
@ -1613,13 +1678,65 @@ L_qm_any:
}
else if (icnt)
{
cent->x = (xt << 4) / icnt;
cent->z = (zt << 4) / icnt;
cent->x = (xt << 4) / icnt + 8;
cent->z = (zt << 4) / icnt + 8;
}
if (icnt >= cond->count)
return COND_OK;
return COND_FAILED;
case F_BIOME_SAMPLE:
if (pass != PASS_FULL_64)
return COND_MAYBE_POS_INVAL;
if (cond->confidence <= 0 || cond->confidence >= 1)
return COND_FAILED;
if (cond->converage <= 0 || cond->converage > 1)
return COND_FAILED;
s = finfo.pow2;
rx1 = x1 >> s;
rz1 = z1 >> s;
rx2 = x2 >> s;
rz2 = z2 >> s;
{
int w = rx2 - rx1 + 1;
int h = rz2 - rz1 + 1;
Range r = {1<<s, rx1, rz1, w, h, s == 0 ? cond->y : cond->y >> 2, 1};
env->init4Dim(DIM_OVERWORLD);
sample_boime_t sample;
sample.cond = cond;
sample.at = at;
sample.n = 0;
sample.xsum = 0;
sample.zsum = 0;
sample.imax = imax;
sample.cent = cent;
sample.stop = abort;
uint64_t rng;
setSeed(&rng, env->seed);
int ok = monteCarloBiomes(
&env->g, r, &rng, cond->converage, cond->confidence,
&f_biome_sampler, &sample);
if (imax)
{
*imax = sample.n;
}
else if (sample.n)
{
cent->x = sample.xsum / sample.n + 2;
cent->z = sample.zsum / sample.n + 2;
}
else
{
*cent = at;
}
return ok == 1 ? COND_OK : COND_FAILED;
}
return COND_FAILED;
// biome filters reference specific layers
// MAYBE: options for layers in different versions?
case F_BIOME:
@ -1632,12 +1749,12 @@ L_qm_any:
if (env->mc >= MC_1_18)
return COND_FAILED;
s = finfo.pow2;
rx1 = ((cond->x1 << s) + at.x) >> s;
rz1 = ((cond->z1 << s) + at.z) >> s;
rx2 = ((cond->x2 << s) + at.x) >> s;
rz2 = ((cond->z2 << s) + at.z) >> s;
cent->x = ((rx1 + rx2) << s) >> 1;
cent->z = ((rz1 + rz2) << s) >> 1;
rx1 = x1 >> s;
rz1 = z1 >> s;
rx2 = x2 >> s;
rz2 = z2 >> s;
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (pass == PASS_FAST_48)
return COND_MAYBE_POS_VALID;
if (pass == PASS_FULL_48)
@ -1663,12 +1780,12 @@ L_qm_any:
case F_TEMPS:
if (env->mc >= MC_1_18)
return COND_FAILED;
rx1 = ((cond->x1 << 10) + at.x) >> 10;
rz1 = ((cond->z1 << 10) + at.z) >> 10;
rx2 = ((cond->x2 << 10) + at.x) >> 10;
rz2 = ((cond->z2 << 10) + at.z) >> 10;
cent->x = ((rx1 + rx2) << 10) >> 1;
cent->z = ((rz1 + rz2) << 10) >> 1;
rx1 = x1 >> 10;
rz1 = z1 >> 10;
rx2 = x2 >> 10;
rz2 = z2 >> 10;
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (pass != PASS_FULL_64)
return COND_MAYBE_POS_VALID;
env->init4Dim(DIM_OVERWORLD);
@ -1692,12 +1809,12 @@ L_qm_any:
L_noise_biome:
s = finfo.pow2;
rx1 = ((cond->x1 << s) + at.x) >> s;
rz1 = ((cond->z1 << s) + at.z) >> s;
rx2 = ((cond->x2 << s) + at.x) >> s;
rz2 = ((cond->z2 << s) + at.z) >> s;
cent->x = ((rx1 + rx2) << s) >> 1;
cent->z = ((rz1 + rz2) << s) >> 1;
rx1 = x1 >> s;
rz1 = z1 >> s;
rx2 = x2 >> s;
rz2 = z2 >> s;
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (pass == PASS_FAST_48)
return COND_MAYBE_POS_VALID;
// the Nether and End require only the 48-bit seed
@ -1720,13 +1837,13 @@ L_noise_biome:
if (pass == PASS_FULL_64)
{
s = finfo.pow2;
rx1 = ((cond->x1 << s) + at.x) >> s;
rz1 = ((cond->z1 << s) + at.z) >> s;
rx2 = ((cond->x2 << s) + at.x) >> s;
rz2 = ((cond->z2 << s) + at.z) >> s;
rx1 = x1 >> s;
rz1 = z1 >> s;
rx2 = x2 >> s;
rz2 = z2 >> s;
int w = rx2 - rx1 + 1;
int h = rz2 - rz1 + 1;
Range r = {finfo.step, rx1, rz1, w, h, cond->y >> 2, 1};
Range r = {1<<s, rx1, rz1, w, h, cond->y >> 2, 1};
env->init4Dim(DIM_OVERWORLD);
if (cond->count == 0)
@ -1737,8 +1854,8 @@ L_noise_biome:
);
if (icnt == 0)
{
cent->x = (rx1 + rx2) << 1;
cent->z = (rz1 + rz2) << 1;
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (imax) *imax = 1;
return COND_OK;
}
@ -1782,8 +1899,8 @@ L_noise_biome:
}
if (j >= cond->count)
{
cent->x = xt / j;
cent->z = zt / j;
cent->x = xt / j + (1 << s) / 2;
cent->z = zt / j + (1 << s) / 2;
return COND_OK;
}
}
@ -1794,10 +1911,10 @@ L_noise_biome:
case F_CLIMATE_MINMAX:
if (env->mc < MC_1_18 || cond->para >= NP_MAX)
return COND_FAILED;
rx1 = ((cond->x1 << 2) + at.x) >> 2;
rz1 = ((cond->z1 << 2) + at.z) >> 2;
rx2 = ((cond->x2 << 2) + at.x) >> 2;
rz2 = ((cond->z2 << 2) + at.z) >> 2;
rx1 = x1 >> 2;
rz1 = z1 >> 2;
rx2 = x2 >> 2;
rz2 = z2 >> 2;
if (pass != PASS_FULL_64)
return COND_MAYBE_POS_INVAL;
{
@ -1836,12 +1953,12 @@ L_noise_biome:
case F_CLIMATE_NOISE:
if (env->mc < MC_1_18)
return COND_FAILED;
rx1 = ((cond->x1 << 2) + at.x) >> 2;
rz1 = ((cond->z1 << 2) + at.z) >> 2;
rx2 = ((cond->x2 << 2) + at.x) >> 2;
rz2 = ((cond->z2 << 2) + at.z) >> 2;
cent->x = ((rx1 + rx2) << 2) >> 1;
cent->z = ((rz1 + rz2) << 2) >> 1;
rx1 = x1 >> 2;
rz1 = z1 >> 2;
rx2 = x2 >> 2;
rz2 = z2 >> 2;
cent->x = (x1 + x2) >> 1;
cent->z = (z1 + z2) >> 1;
if (pass != PASS_FULL_64)
return COND_MAYBE_POS_VALID;
{
@ -1897,10 +2014,10 @@ L_noise_biome:
case F_HEIGHT:
rx1 = ((cond->x1 << 2) + at.x) >> 2;
rz1 = ((cond->z1 << 2) + at.z) >> 2;
cent->x = rx1 << 2;
cent->z = rz1 << 2;
rx1 = x1 >> 2;
rz1 = z1 >> 2;
cent->x = x1;
cent->z = z1;
if (pass != PASS_FULL_64)
return COND_MAYBE_POS_VALID;
env->init4Dim(DIM_OVERWORLD);
@ -2015,3 +2132,4 @@ void findQuadStructs(int styp, Generator *g, QVector<QuadInfo> *out)

View File

@ -69,7 +69,7 @@ enum
F_PORTALN,
F_GATEWAY,
F_MINESHAFT,
F_SPIRAL_1,
F_SPIRAL,
F_SPIRAL_16,
F_SPIRAL_64,
F_SPIRAL_256,
@ -91,22 +91,35 @@ enum
F_LUA,
F_WELL,
F_TRAILS,
F_BIOME_SAMPLE,
// new filters should be added here at the end to keep some downwards compatibility
FILTER_MAX,
};
struct FilterInfo
{
enum {
LOC_1 = 1, LOC_2 = 2, LOC_R = 4,
LOC_NIL = 0x0,
LOC_POS = 0x1,
LOC_REC = 0x3,
LOC_RAD = 0x7,
};
enum {
BR_NONE = 0, // one position - no branching
BR_FIRST = 1, // choose only first, no branching
BR_SPLIT = 2, // branches are examined separately
BR_CLUST = 3, // allow clustering to avoid branching
};
int cat; // seed source category
bool dep64; // depends on 64-bit seed
bool coord; // requires coordinate entry
bool area; // requires area entry
bool rmax; // supports radial range
int loc;
int layer; // associated generator layer
int stype; // structure type
int step; // coordinate multiplier
int pow2; // bit position of step
int count; // can have instances
int grid; // coordinate multiplier
int pow2; // bit position of grid
int branch; // branching behaviour
int mcmin; // minimum version
int mcmax; // maximum version
int dim; // dimension
@ -118,7 +131,7 @@ struct FilterInfo
};
// global table of filter data (as constants with enum indexing)
static const struct FilterList
static const struct FilterList : private FilterInfo
{
FilterInfo list[FILTER_MAX];
@ -127,13 +140,13 @@ static const struct FilterList
int disp = 0; // display order
list[F_SELECT] = FilterInfo{
CAT_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, MC_UNDEF, MC_NEWEST, 0, 0, disp++,
CAT_NONE, 0, LOC_NIL, 0, 0, 0, 0, BR_NONE, MC_UNDEF, MC_NEWEST, 0, 0, disp++,
NULL,
"",
""
};
list[F_LOGIC_OR] = FilterInfo{
CAT_HELPER, 0, 0, 0, 0, 0, 0, 1, 0, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"helper",
QT_TRANSLATE_NOOP("Filter", "OR logic gate"),
QT_TRANSLATE_NOOP("Filter",
@ -142,7 +155,7 @@ static const struct FilterList
"defined, it defaults to true.")
};
list[F_LOGIC_NOT] = FilterInfo{
CAT_HELPER, 0, 0, 0, 0, 0, 0, 1, 0, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"helper",
QT_TRANSLATE_NOOP("Filter", "NOT logic gate"),
QT_TRANSLATE_NOOP("Filter",
@ -151,79 +164,41 @@ static const struct FilterList
"defined, it defaults to true.")
};
list[F_LUA] = FilterInfo{
CAT_HELPER, 0, 0, 0, 0, 0, 0, 1, 0, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"helper",
QT_TRANSLATE_NOOP("Filter", "Lua"),
QT_TRANSLATE_NOOP("Filter",
"Define custom conditions using Lua scripts.")
};
list[F_SCALE_TO_NETHER] = FilterInfo{
CAT_HELPER, 0, 0, 0, 0, 0, 0, 1, 0, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"portal_lit",
QT_TRANSLATE_NOOP("Filter", "Coordinate factor x/8"),
QT_TRANSLATE_NOOP("Filter",
"Divides relative location by 8, from Overworld to Nether.")
};
list[F_SCALE_TO_OVERWORLD] = FilterInfo{
CAT_HELPER, 0, 0, 0, 0, 0, 0, 1, 0, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"portal_lit",
QT_TRANSLATE_NOOP("Filter", "Coordinate factor x*8"),
QT_TRANSLATE_NOOP("Filter",
"Multiplies relative location by 8, from Nether to Overworld.")
};
const char *spiral_desc = QT_TRANSLATE_NOOP("Filter",
list[F_SPIRAL] = FilterInfo{
CAT_HELPER, 0, LOC_RAD, 0, 0, 1, 0, BR_FIRST, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator"),
QT_TRANSLATE_NOOP("Filter",
"<html><head/><body>"
"Spiral iterator conditions can be used to move a testing position across "
"a given area using a certain step size. Other conditions that refer to it "
"as a relative location will be checked at each step. The iteration is "
"performed in a spiral, so positions closer to the center get priority."
"</body></html>"
);
list[F_SPIRAL_1] = FilterInfo{
CAT_HELPER, 0, 1, 1, 0, 0, 0, 1, 0, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator 1:1"),
spiral_desc
};
list[F_SPIRAL_4] = FilterInfo{
CAT_HELPER, 0, 1, 1, 0, 0, 0, 4, 2, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator 1:4"),
spiral_desc
};
list[F_SPIRAL_16] = FilterInfo{
CAT_HELPER, 0, 1, 1, 0, 0, 0, 16, 4, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator 1:16"),
spiral_desc
};
list[F_SPIRAL_64] = FilterInfo{
CAT_HELPER, 0, 1, 1, 0, 0, 0, 64, 6, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator 1:64"),
spiral_desc
};
list[F_SPIRAL_256] = FilterInfo{
CAT_HELPER, 0, 1, 1, 0, 0, 0, 256, 8, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator 1:256"),
spiral_desc
};
list[F_SPIRAL_512] = FilterInfo{
CAT_HELPER, 0, 1, 1, 0, 0, 0, 512, 9, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator 1:512"),
spiral_desc
};
list[F_SPIRAL_1024] = FilterInfo{
CAT_HELPER, 0, 1, 1, 0, 0, 0, 1024, 10, 0, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++,
"reference",
QT_TRANSLATE_NOOP("Filter", "Spiral iterator 1:1024"),
spiral_desc
"</body></html>")
};
list[F_QH_IDEAL] = FilterInfo{
CAT_QUAD, 0, 1, 1, 0, 0, Swamp_Hut, 512, 9, 0, MC_1_4, MC_NEWEST, 0, 0, disp++,
CAT_QUAD, 0, LOC_REC, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++,
"quad",
QT_TRANSLATE_NOOP("Filter", "Quad-hut (ideal)"),
QT_TRANSLATE_NOOP("Filter",
@ -232,7 +207,7 @@ static const struct FilterList
};
list[F_QH_CLASSIC] = FilterInfo{
CAT_QUAD, 0, 1, 1, 0, 0, Swamp_Hut, 512, 9, 0, MC_1_4, MC_NEWEST, 0, 0, disp++,
CAT_QUAD, 0, LOC_REC, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++,
"quad",
QT_TRANSLATE_NOOP("Filter", "Quad-hut (classic)"),
QT_TRANSLATE_NOOP("Filter",
@ -243,7 +218,7 @@ static const struct FilterList
};
list[F_QH_NORMAL] = FilterInfo{
CAT_QUAD, 0, 1, 1, 0, 0, Swamp_Hut, 512, 9, 0, MC_1_4, MC_NEWEST, 0, 0, disp++,
CAT_QUAD, 0, LOC_REC, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++,
"quad",
QT_TRANSLATE_NOOP("Filter", "Quad-hut (normal)"),
QT_TRANSLATE_NOOP("Filter",
@ -254,7 +229,7 @@ static const struct FilterList
};
list[F_QH_BARELY] = FilterInfo{
CAT_QUAD, 0, 1, 1, 0, 0, Swamp_Hut, 512, 9, 0, MC_1_4, MC_NEWEST, 0, 0, disp++,
CAT_QUAD, 0, LOC_REC, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++,
"quad",
QT_TRANSLATE_NOOP("Filter", "Quad-hut (barely)"),
QT_TRANSLATE_NOOP("Filter",
@ -264,7 +239,7 @@ static const struct FilterList
};
list[F_QM_95] = FilterInfo{
CAT_QUAD, 0, 1, 1, 0, 0, Monument, 512, 9, 0, MC_1_8, MC_NEWEST, 0, 0, disp++,
CAT_QUAD, 0, LOC_REC, 0, Monument, 512, 9, BR_FIRST, MC_1_8, MC_NEWEST, 0, 0, disp++,
"quad",
QT_TRANSLATE_NOOP("Filter", "Quad-ocean-monument (>95%)"),
QT_TRANSLATE_NOOP("Filter",
@ -274,7 +249,7 @@ static const struct FilterList
};
list[F_QM_90] = FilterInfo{
CAT_QUAD, 0, 1, 1, 0, 0, Monument, 512, 9, 0, MC_1_8, MC_NEWEST, 0, 0, disp++,
CAT_QUAD, 0, LOC_REC, 0, Monument, 512, 9, BR_FIRST, MC_1_8, MC_NEWEST, 0, 0, disp++,
"quad",
QT_TRANSLATE_NOOP("Filter", "Quad-ocean-monument (>90%)"),
QT_TRANSLATE_NOOP("Filter",
@ -283,8 +258,17 @@ static const struct FilterList
"location.")
};
list[F_BIOME_SAMPLE] = FilterInfo{
CAT_BIOMES, 1, LOC_RAD, 0, 0, 1, 0, BR_SPLIT, MC_B1_7, MC_NEWEST, 0, 1, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Biome samples"),
QT_TRANSLATE_NOOP("Filter",
"Samples biomes in a given area to find if a proportion of the "
"biomes match a set of allowed biomes.")
};
list[F_BIOME] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, L_VORONOI_1, 0, 1, 0, 0, MC_B1_7, MC_1_17, 0, 1, disp++, // disable for 1.18
CAT_BIOMES, 1, LOC_REC, L_VORONOI_1, 0, 1, 0, BR_NONE, MC_B1_7, MC_1_17, 0, 1, disp++, // disable for 1.18
"map",
QT_TRANSLATE_NOOP("Filter", "Biomes 1:1"),
QT_TRANSLATE_NOOP("Filter",
@ -293,7 +277,7 @@ static const struct FilterList
};
list[F_BIOME_4] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, 0, 0, 4, 2, 0, MC_B1_7, MC_NEWEST, 0, 1, disp++,
CAT_BIOMES, 1, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Biomes 1:4"),
QT_TRANSLATE_NOOP("Filter",
@ -301,7 +285,7 @@ static const struct FilterList
"discard those that have biomes that are explicitly excluded (-).")
};
list[F_BIOME_16] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, 0, 0, 16, 4, 0, MC_B1_7, MC_NEWEST, 0, 1, disp++,
CAT_BIOMES, 1, LOC_REC, 0, 0, 16, 4, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Biomes 1:16"),
QT_TRANSLATE_NOOP("Filter",
@ -309,7 +293,7 @@ static const struct FilterList
"discard those that have biomes that are explicitly excluded (-).")
};
list[F_BIOME_64] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, 0, 0, 64, 6, 0, MC_B1_7, MC_NEWEST, 0, 1, disp++,
CAT_BIOMES, 1, LOC_REC, 0, 0, 64, 6, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Biomes 1:64"),
QT_TRANSLATE_NOOP("Filter",
@ -317,7 +301,7 @@ static const struct FilterList
"discard those that have biomes that are explicitly excluded (-).")
};
list[F_BIOME_256] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, 0, 0, 256, 8, 0, MC_B1_7, MC_NEWEST, 0, 1, disp++,
CAT_BIOMES, 1, LOC_REC, 0, 0, 256, 8, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Biomes 1:256"),
QT_TRANSLATE_NOOP("Filter",
@ -326,7 +310,7 @@ static const struct FilterList
};
list[F_BIOME_4_RIVER] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, L_RIVER_MIX_4, 0, 4, 2, 0, MC_1_13, MC_1_17, 0, 0, disp++,
CAT_BIOMES, 1, LOC_REC, L_RIVER_MIX_4, 0, 4, 2, BR_NONE, MC_1_13, MC_1_17, 0, 0, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Biomes 1:4 RIVER"),
QT_TRANSLATE_NOOP("Filter",
@ -336,7 +320,7 @@ static const struct FilterList
"This layer does not generate ocean variants.")
};
list[F_BIOME_256_OTEMP] = FilterInfo{
CAT_BIOMES, 0, 1, 1, 0, L_OCEAN_TEMP_256, 0, 256, 8, 0, MC_1_13, MC_1_17, 0, 0, disp++,
CAT_BIOMES, 0, LOC_REC, L_OCEAN_TEMP_256, 0, 256, 8, BR_NONE, MC_1_13, MC_1_17, 0, 0, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Biomes 1:256 O.TEMP"),
QT_TRANSLATE_NOOP("Filter",
@ -346,7 +330,7 @@ static const struct FilterList
"This generation layer depends only on the lower 48-bits of the seed.")
};
list[F_CLIMATE_NOISE] = FilterInfo{
CAT_BIOMES, 0, 1, 1, 0, 0, 0, 4, 2, 0, MC_1_18, MC_NEWEST, 0, 0, disp++,
CAT_BIOMES, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_18, MC_NEWEST, 0, 0, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Climate parameters 1:4"),
QT_TRANSLATE_NOOP("Filter",
@ -354,28 +338,28 @@ static const struct FilterList
"the specified area should cover.")
};
list[F_CLIMATE_MINMAX] = FilterInfo{
CAT_BIOMES, 0, 1, 1, 0, 0, 0, 4, 2, 0, MC_1_18, MC_NEWEST, 0, 0, disp++,
CAT_BIOMES, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_18, MC_NEWEST, 0, 0, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Locate climate extreme 1:4"),
QT_TRANSLATE_NOOP("Filter",
"Finds the location where a climate parameter reaches its minimum or maximum.")
};
list[F_BIOME_CENTER] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, 0, 0, 4, 2, 1, MC_B1_7, MC_NEWEST, 0, 1, disp++,
CAT_BIOMES, 1, LOC_REC, 0, 0, 4, 2, BR_CLUST, MC_B1_7, MC_NEWEST, 0, 1, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Locate biome center 1:4"),
QT_TRANSLATE_NOOP("Filter",
"Finds the center position of a given biome.")
};
list[F_BIOME_CENTER_256] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, 0, 0, 256, 8, 1, MC_B1_7, MC_1_17, 0, 1, disp++,
CAT_BIOMES, 1, LOC_REC, 0, 0, 256, 8, BR_CLUST, MC_B1_7, MC_1_17, 0, 1, disp++,
"map",
QT_TRANSLATE_NOOP("Filter", "Locate biome center 1:256"),
QT_TRANSLATE_NOOP("Filter",
"Finds the center position of a given biome. Based on the 1:256 biome layer.")
};
list[F_TEMPS] = FilterInfo{
CAT_BIOMES, 1, 1, 1, 0, 0, 0, 1024, 10, 0, MC_1_7, MC_1_17, 0, 0, disp++,
CAT_BIOMES, 1, LOC_REC, 0, 0, 1024, 10, BR_NONE, MC_1_7, MC_1_17, 0, 0, disp++,
"tempcat",
QT_TRANSLATE_NOOP("Filter", "Temperature categories"),
QT_TRANSLATE_NOOP("Filter",
@ -383,35 +367,35 @@ static const struct FilterList
};
list[F_BIOME_NETHER_1] = FilterInfo{
CAT_NETHER, 1, 1, 1, 0, 0, 0, 1, 0, 0, MC_1_16_1, 0, -1, 1, disp++, // disabled
CAT_NETHER, 1, LOC_REC, 0, 0, 1, 0, BR_NONE, MC_1_16_1, 0, -1, 1, disp++, // disabled
"nether",
QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:1 (disabled)"),
QT_TRANSLATE_NOOP("Filter",
"Nether biomes after voronoi scaling to 1:1.")
};
list[F_BIOME_NETHER_4] = FilterInfo{
CAT_NETHER, 0, 1, 1, 0, 0, 0, 4, 2, 0, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
CAT_NETHER, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
"nether",
QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:4"),
QT_TRANSLATE_NOOP("Filter",
"Nether biomes with normal noise sampling at scale 1:4.")
};
list[F_BIOME_NETHER_16] = FilterInfo{
CAT_NETHER, 0, 1, 1, 0, 0, 0, 16, 4, 0, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
CAT_NETHER, 0, LOC_REC, 0, 0, 16, 4, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
"nether",
QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:16"),
QT_TRANSLATE_NOOP("Filter",
"Nether biomes, but only sampled at scale 1:16.")
};
list[F_BIOME_NETHER_64] = FilterInfo{
CAT_NETHER, 0, 1, 1, 0, 0, 0, 64, 6, 0, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
CAT_NETHER, 0, LOC_REC, 0, 0, 64, 6, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
"nether",
QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:64"),
QT_TRANSLATE_NOOP("Filter",
"Nether biomes, but only sampled at scale 1:64.")
};
list[F_BIOME_NETHER_256] = FilterInfo{
CAT_NETHER, 0, 1, 1, 0, 0, 0, 256, 8, 0, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
CAT_NETHER, 0, LOC_REC, 0, 0, 256, 8, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
"nether",
QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:256"),
QT_TRANSLATE_NOOP("Filter",
@ -419,28 +403,28 @@ static const struct FilterList
};
list[F_BIOME_END_1] = FilterInfo{
CAT_END, 1, 1, 1, 0, 0, 0, 1, 0, 0, MC_1_9, 0, +1, 1, disp++, // disabled
CAT_END, 1, LOC_REC, 0, 0, 1, 0, BR_NONE, MC_1_9, 0, +1, 1, disp++, // disabled
"the_end",
QT_TRANSLATE_NOOP("Filter", "End biomes 1:1 (disabled)"),
QT_TRANSLATE_NOOP("Filter",
"End biomes after voronoi scaling to 1:1.")
};
list[F_BIOME_END_4] = FilterInfo{
CAT_END, 0, 1, 1, 0, 0, 0, 4, 2, 0, MC_1_9, MC_NEWEST, +1, 0, disp++,
CAT_END, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_9, MC_NEWEST, +1, 0, disp++,
"the_end",
QT_TRANSLATE_NOOP("Filter", "End biomes 1:4"),
QT_TRANSLATE_NOOP("Filter",
"End biomes sampled at scale 1:4. Note this is just a simple upscale of 1:16.")
};
list[F_BIOME_END_16] = FilterInfo{
CAT_END, 0, 1, 1, 0, 0, 0, 16, 4, 0, MC_1_9, MC_NEWEST, +1, 0, disp++,
CAT_END, 0, LOC_REC, 0, 0, 16, 4, BR_NONE, MC_1_9, MC_NEWEST, +1, 0, disp++,
"the_end",
QT_TRANSLATE_NOOP("Filter", "End biomes 1:16"),
QT_TRANSLATE_NOOP("Filter",
"End biomes with normal sampling at scale 1:16.")
};
list[F_BIOME_END_64] = FilterInfo{
CAT_END, 0, 1, 1, 0, 0, 0, 64, 6, 0, MC_1_9, MC_NEWEST, +1, 0, disp++,
CAT_END, 0, LOC_REC, 0, 0, 64, 6, BR_NONE, MC_1_9, MC_NEWEST, +1, 0, disp++,
"the_end",
QT_TRANSLATE_NOOP("Filter", "End biomes 1:64"),
QT_TRANSLATE_NOOP("Filter",
@ -448,20 +432,20 @@ static const struct FilterList
};
list[F_SPAWN] = FilterInfo{
CAT_OTHER, 1, 1, 1, 1, 0, 0, 1, 0, 0, MC_B1_8, MC_NEWEST, 0, 0, disp++,
CAT_OTHER, 1, LOC_RAD, 0, 0, 1, 0, BR_NONE, MC_B1_8, MC_NEWEST, 0, 0, disp++,
"spawn",
QT_TRANSLATE_NOOP("Filter", "Spawn"),
""
};
list[F_SLIME] = FilterInfo{
CAT_OTHER, 0, 1, 1, 0, 0, 0, 16, 4, 1, MC_UNDEF, MC_NEWEST, 0, 0, disp++,
CAT_OTHER, 0, LOC_REC, 0, 0, 16, 4, BR_CLUST, MC_UNDEF, MC_NEWEST, 0, 0, disp++,
"slime",
QT_TRANSLATE_NOOP("Filter", "Slime chunk"),
""
};
list[F_HEIGHT] = FilterInfo{
CAT_OTHER, 0, 1, 0, 0, 0, 0, 4, 2, 0, MC_1_1, MC_NEWEST, 0, 0, disp++,
CAT_OTHER, 0, LOC_POS, 0, 0, 4, 2, BR_NONE, MC_1_1, MC_NEWEST, 0, 0, disp++,
"height",
QT_TRANSLATE_NOOP("Filter", "Surface height"),
QT_TRANSLATE_NOOP("Filter",
@ -469,7 +453,7 @@ static const struct FilterList
};
list[F_FIRST_STRONGHOLD] = FilterInfo{
CAT_OTHER, 0, 1, 1, 1, 0, 0, 1, 0, 0, MC_B1_8, MC_NEWEST, 0, 0, disp++,
CAT_OTHER, 0, LOC_RAD, 0, 0, 1, 0, BR_NONE, MC_B1_8, MC_NEWEST, 0, 0, disp++,
"stronghold",
QT_TRANSLATE_NOOP("Filter", "First stronghold"),
QT_TRANSLATE_NOOP("Filter",
@ -478,28 +462,28 @@ static const struct FilterList
};
list[F_STRONGHOLD] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, 0, 1, 0, 1, MC_B1_8, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, 0, 1, 0, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++,
"stronghold",
QT_TRANSLATE_NOOP("Filter", "Stronghold"),
""
};
list[F_VILLAGE] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Village, 1, 0, 1, MC_B1_8, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Village, 1, 0, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++,
"village",
QT_TRANSLATE_NOOP("Filter", "Village"),
""
};
list[F_MINESHAFT] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 0, 0, Mineshaft, 1, 0, 1, MC_B1_8, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Mineshaft, 1, 0, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++,
"mineshaft",
QT_TRANSLATE_NOOP("Filter", "Abandoned mineshaft"),
""
};
list[F_DESERT] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Desert_Pyramid, 1, 0, 1, MC_1_3, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Desert_Pyramid, 1, 0, BR_CLUST, MC_1_3, MC_NEWEST, 0, 0, disp++,
"desert",
QT_TRANSLATE_NOOP("Filter", "Desert pyramid"),
QT_TRANSLATE_NOOP("Filter",
@ -508,7 +492,7 @@ static const struct FilterList
};
list[F_JUNGLE] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Jungle_Temple, 1, 0, 1, MC_1_3, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Jungle_Temple, 1, 0, BR_CLUST, MC_1_3, MC_NEWEST, 0, 0, disp++,
"jungle",
QT_TRANSLATE_NOOP("Filter", "Jungle temple"),
QT_TRANSLATE_NOOP("Filter",
@ -517,28 +501,28 @@ static const struct FilterList
};
list[F_HUT] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Swamp_Hut, 1, 0, 1, MC_1_4, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Swamp_Hut, 1, 0, BR_CLUST, MC_1_4, MC_NEWEST, 0, 0, disp++,
"hut",
QT_TRANSLATE_NOOP("Filter", "Swamp hut"),
""
};
list[F_MONUMENT] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Monument, 1, 0, 1, MC_1_8, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Monument, 1, 0, BR_CLUST, MC_1_8, MC_NEWEST, 0, 0, disp++,
"monument",
QT_TRANSLATE_NOOP("Filter", "Ocean monument"),
""
};
list[F_IGLOO] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Igloo, 1, 0, 1, MC_1_9, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Igloo, 1, 0, BR_CLUST, MC_1_9, MC_NEWEST, 0, 0, disp++,
"igloo",
QT_TRANSLATE_NOOP("Filter", "Igloo"),
""
};
list[F_MANSION] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Mansion, 1, 0, 1, MC_1_11, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Mansion, 1, 0, BR_CLUST, MC_1_11, MC_NEWEST, 0, 0, disp++,
"mansion",
QT_TRANSLATE_NOOP("Filter", "Woodland mansion"),
QT_TRANSLATE_NOOP("Filter",
@ -547,21 +531,21 @@ static const struct FilterList
};
list[F_RUINS] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Ocean_Ruin, 1, 0, 1, MC_1_13, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Ocean_Ruin, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++,
"ruins",
QT_TRANSLATE_NOOP("Filter", "Ocean ruins"),
""
};
list[F_SHIPWRECK] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Shipwreck, 1, 0, 1, MC_1_13, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Shipwreck, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++,
"shipwreck",
QT_TRANSLATE_NOOP("Filter", "Shipwreck"),
""
};
list[F_TREASURE] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Treasure, 1, 0, 1, MC_1_13, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Treasure, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++,
"treasure",
QT_TRANSLATE_NOOP("Filter", "Buried treasure"),
QT_TRANSLATE_NOOP("Filter",
@ -571,70 +555,70 @@ static const struct FilterList
};
list[F_WELL] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Desert_Well, 1, 0, 1, MC_1_13, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Desert_Well, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++,
"well",
QT_TRANSLATE_NOOP("Filter", "Desert well"),
""
};
list[F_OUTPOST] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Outpost, 1, 0, 1, MC_1_14, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Outpost, 1, 0, BR_CLUST, MC_1_14, MC_NEWEST, 0, 0, disp++,
"outpost",
QT_TRANSLATE_NOOP("Filter", "Pillager outpost"),
""
};
list[F_ANCIENT_CITY] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Ancient_City, 1, 0, 1, MC_1_19, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Ancient_City, 1, 0, BR_CLUST, MC_1_19, MC_NEWEST, 0, 0, disp++,
"ancient_city",
QT_TRANSLATE_NOOP("Filter", "Ancient city"),
""
};
list[F_TRAILS] = FilterInfo{
CAT_STRUCT, 1, 1, 1, 1, 0, Trail_Ruin, 1, 0, 1, MC_1_20, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 1, LOC_RAD, 0, Trail_Ruin, 1, 0, BR_CLUST, MC_1_20, MC_NEWEST, 0, 0, disp++,
"trails",
QT_TRANSLATE_NOOP("Filter", "Trail ruins"),
""
};
list[F_PORTAL] = FilterInfo{
CAT_STRUCT, 0, 1, 1, 1, 0, Ruined_Portal, 1, 0, 1, MC_1_16_1, MC_NEWEST, 0, 0, disp++,
CAT_STRUCT, 0, LOC_RAD, 0, Ruined_Portal, 1, 0, BR_CLUST, MC_1_16_1, MC_NEWEST, 0, 0, disp++,
"portal",
QT_TRANSLATE_NOOP("Filter", "Ruined portal (overworld)"),
""
};
list[F_PORTALN] = FilterInfo{
CAT_STRUCT, 0, 1, 1, 1, 0, Ruined_Portal_N, 1, 0, 1, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
CAT_STRUCT, 0, LOC_RAD, 0, Ruined_Portal_N, 1, 0, BR_CLUST, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
"portal",
QT_TRANSLATE_NOOP("Filter", "Ruined portal (nether)"),
""
};
list[F_FORTRESS] = FilterInfo{
CAT_STRUCT, 0, 1, 1, 1, 0, Fortress, 1, 0, 1, MC_1_0, MC_NEWEST, -1, 0, disp++,
CAT_STRUCT, 0, LOC_RAD, 0, Fortress, 1, 0, BR_CLUST, MC_1_0, MC_NEWEST, -1, 0, disp++,
"fortress",
QT_TRANSLATE_NOOP("Filter", "Nether fortress"),
""
};
list[F_BASTION] = FilterInfo{
CAT_STRUCT, 0, 1, 1, 1, 0, Bastion, 1, 0, 1, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
CAT_STRUCT, 0, LOC_RAD, 0, Bastion, 1, 0, BR_CLUST, MC_1_16_1, MC_NEWEST, -1, 0, disp++,
"bastion",
QT_TRANSLATE_NOOP("Filter", "Bastion remnant"),
""
};
list[F_ENDCITY] = FilterInfo{
CAT_STRUCT, 0, 1, 1, 1, 0, End_City, 1, 0, 1, MC_1_9, MC_NEWEST, +1, 0, disp++,
CAT_STRUCT, 0, LOC_RAD, 0, End_City, 1, 0, BR_CLUST, MC_1_9, MC_NEWEST, +1, 0, disp++,
"endcity",
QT_TRANSLATE_NOOP("Filter", "End city"),
""
};
list[F_GATEWAY] = FilterInfo{
CAT_STRUCT, 0, 1, 1, 1, 0, End_Gateway, 1, 0, 1, MC_1_13, MC_NEWEST, +1, 0, disp++,
CAT_STRUCT, 0, LOC_RAD, 0, End_Gateway, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, +1, 0, disp++,
"gateway",
QT_TRANSLATE_NOOP("Filter", "End gateway"),
QT_TRANSLATE_NOOP("Filter",
@ -656,7 +640,8 @@ struct /*__attribute__((packed))*/ Condition
VER_2_3_0 = 1,
VER_2_4_0 = 2,
VER_3_4_0 = 3,
VER_CURRENT = VER_3_4_0,
VER_4_0_0 = 4,
VER_CURRENT = VER_4_0_0,
};
enum { // meta flags
DISABLED = 0x0001,
@ -699,7 +684,7 @@ struct /*__attribute__((packed))*/ Condition
uint8_t minmax;
uint8_t para;
uint8_t octave;
uint8_t pad2[2]; // legacy zero initialized
uint16_t step;
uint16_t version; // condition data version
uint64_t biomeToExcl, biomeToExclM; // exclusion biomes
int32_t temps[9];
@ -714,6 +699,8 @@ struct /*__attribute__((packed))*/ Condition
int32_t limex[NP_MAX][2];
float vmin;
float vmax;
float converage;
float confidence;
// generated members - initialized when the search is started
uint8_t generated_start[0]; // address dummy
@ -732,7 +719,7 @@ struct /*__attribute__((packed))*/ Condition
};
static_assert(
offsetof(Condition, generated_start) == 312,
offsetof(Condition, generated_start) == 320,
"Layout of Condition has changed!"
);

View File

@ -261,7 +261,7 @@ bool SearchMaster::set(QWidget *widget, const Session& s)
{
Generator tmp;
setupGenerator(&tmp, s.wi.mc, 0);
const Layer *l = getLayerForScale(&tmp, finfo.step);
const Layer *l = getLayerForScale(&tmp, finfo.grid);
if (l)
layerId = l - tmp.ls.layers;
}
@ -281,12 +281,12 @@ bool SearchMaster::set(QWidget *widget, const Session& s)
}
if (c.type == F_TEMPS)
{
int w = c.x2 - c.x1 + 1;
int h = c.z2 - c.z1 + 1;
int w = (c.x2 >> 10) - (c.x1 >> 10) + 1;
int h = (c.z2 >> 10) - (c.z1 >> 10) + 1;
if (c.count > w * h)
{
QString msg = tr("Temperature category condition with ID %1 has too "
"many restrictions (%2) for the area (%3 x %4).");
"many restrictions (%2) for the area (%3 x %4 @ scale 1:1024).");
warn(widget, msg.arg(cid).arg(c.count).arg(w).arg(h));
return false;
}
@ -733,6 +733,7 @@ void SearchMaster::stop()
}
}
workers.clear();
emit searchFinish(false);
}

View File

@ -836,17 +836,14 @@ void TabBiomes::on_pushExport_clicked()
void TabBiomes::on_buttonFromVisible_clicked()
{
MapView *mapview = parent->getMapView();
qreal uiw = mapview->width() * mapview->getScale();
qreal uih = mapview->height() * mapview->getScale();
int bx0 = (int) floor(mapview->getX() - uiw/2);
int bz0 = (int) floor(mapview->getZ() - uih/2);
int bx1 = (int) ceil(mapview->getX() + uiw/2);
int bz1 = (int) ceil(mapview->getZ() + uih/2);
ui->lineX1->setText( QString::number(bx0) );
ui->lineZ1->setText( QString::number(bz0) );
ui->lineX2->setText( QString::number(bx1) );
ui->lineZ2->setText( QString::number(bz1) );
int x1, z1, x2, z2;
mapview->getVisible(&x1, &z1, &x2, &z2);
ui->lineX1->setText( QString::number(x1) );
ui->lineZ1->setText( QString::number(z1) );
ui->lineX2->setText( QString::number(x2) );
ui->lineZ2->setText( QString::number(z2) );
}
void TabBiomes::on_radioFullSample_toggled(bool checked)

437
src/tablocations.cpp Normal file
View File

@ -0,0 +1,437 @@
#include "tablocations.h"
#include "ui_tablocations.h"
#include "message.h"
#include "util.h"
#include "config.h"
#include <QElapsedTimer>
#include <QFileDialog>
#include <QTextStream>
#include <QFileInfo>
#include <QIntValidator>
#include <vector>
#include <algorithm>
#include <random>
#define SAMPLES_MAX 9999999
static
QTreeWidgetItem *setConditionTreeItems(ConditionTree& ctree, int node, int64_t seed, Pos cpos[], QTreeWidgetItem* parent, bool posval)
{
Condition& c = ctree.condvec[node];
Pos p = cpos[c.save];
const std::vector<char>& branches = ctree.references[c.save];
QTreeWidgetItem* item;
if (c.type == 0)
{
item = parent;
}
else
{
item = new QTreeWidgetItem(parent);
item->setText(0, c.summary(false));
if ((p.x == -1 && p.z == -1) || c.type == F_LOGIC_NOT)
posval = false;
if (posval)
{
const FilterInfo& finfo = g_filterinfo.list[c.type];
double dist = sqrt((double)p.x*p.x + (double)p.z*p.z);
item->setText(1, QString::number(p.x));
item->setText(2, QString::number(p.z));
item->setText(3, QString::asprintf("%.0f", dist));
item->setData(0, Qt::UserRole+0, QVariant::fromValue(seed));
item->setData(0, Qt::UserRole+1, QVariant::fromValue(finfo.dim));
item->setData(0, Qt::UserRole+2, QVariant::fromValue(p));
}
}
if (!branches.empty())
{
for (char b : branches)
setConditionTreeItems(ctree, b, seed, cpos, item, posval);
}
return item;
}
QString AnalysisLocations::set(WorldInfo wi, const QVector<Condition>& conds)
{
this->wi = wi;
QString err = condtree.set(conds, wi.mc);
if (err.isEmpty())
err = env.init(wi.mc, wi.large, &condtree);
if (!err.isEmpty())
env.setSeed(wi.seed);
return err;
}
void AnalysisLocations::run()
{
stop = false;
for (idx = 0; idx < (long)pos.size(); idx++)
{
if (stop) break;
Pos at = pos[idx.load()];
Pos cpos[MAX_INSTANCES] = {};
if (testTreeAt(at, &env, PASS_FULL_64, &stop, cpos)
!= COND_OK)
{
continue;
}
double dist = sqrt((double)at.x*at.x + (double)at.z*at.z);
QTreeWidgetItem *item = new QTreeWidgetItem();
item->setText(0, tr("origin"));
item->setText(1, QString::number(at.x));
item->setText(2, QString::number(at.z));
item->setText(3, QString::asprintf("%.0f", dist));
item->setData(0, Qt::UserRole+0, QVariant::fromValue(env.seed));
item->setData(0, Qt::UserRole+1, QVariant::Invalid);
item->setData(0, Qt::UserRole+2, QVariant::fromValue(at));
setConditionTreeItems(condtree, 0, env.seed, cpos, item, true);
emit itemDone(item);
}
}
enum { SMODE_RADIAL_GRID, SMODE_SQUARE_SPIRAL, SMODE_NORMAL };
TabLocations::TabLocations(MainWindow *parent)
: QWidget(parent)
, ui(new Ui::TabLocations)
, parent(parent)
, thread()
, timer()
, maxresults(1)
, nextupdate()
, updt(20)
{
ui->setupUi(this);
ui->treeWidget->setSortingEnabled(false); // sortable triggers are not necessary
ui->comboSampling->addItem(tr("Lattice points in radial order") + ", ||α·n, α·m|| < r", SMODE_RADIAL_GRID);
ui->comboSampling->addItem(tr("Square spiral") + ", (α·n, α·m)", SMODE_SQUARE_SPIRAL);
ui->comboSampling->addItem(tr("Random Gaussian samples") + ", (α·norm(), α·norm())", SMODE_NORMAL);
ui->lineN->setValidator(new QIntValidator(1, SAMPLES_MAX, this));
ui->lineA->setValidator(new QIntValidator(1, (int)3e7, this));
ui->lineX->setValidator(new QIntValidator((int)-3e7, (int)3e7, this));
ui->lineZ->setValidator(new QIntValidator((int)-3e7, (int)3e7, this));
connect(&thread, &AnalysisLocations::warning, this, &TabLocations::warning, Qt::BlockingQueuedConnection);
connect(&thread, &AnalysisLocations::itemDone, this, &TabLocations::onAnalysisItemDone, Qt::BlockingQueuedConnection);
connect(&thread, &AnalysisLocations::finished, this, &TabLocations::onAnalysisFinished);
connect(&timer, &QTimer::timeout, this, QOverload<>::of(&TabLocations::onProgressTimeout));
}
TabLocations::~TabLocations()
{
timer.stop();
thread.stop = true;
thread.wait(500);
delete ui;
}
bool TabLocations::event(QEvent *e)
{
if (e->type() == QEvent::LayoutRequest)
{
QFontMetrics fm = QFontMetrics(ui->treeWidget->font());
ui->treeWidget->setColumnWidth(0, fm.horizontalAdvance('#') * 32);
ui->treeWidget->setColumnWidth(1, fm.horizontalAdvance('#') * 9);
ui->treeWidget->setColumnWidth(2, fm.horizontalAdvance('#') * 9);
ui->treeWidget->setColumnWidth(3, fm.horizontalAdvance('#') * 9);
}
return QWidget::event(e);
}
void TabLocations::save(QSettings& settings)
{
settings.setValue("analysis/samplemode", ui->comboSampling->currentData().toInt());
settings.setValue("analysis/samplecnt", ui->lineN->text().toInt());
settings.setValue("analysis/samplesep", ui->lineA->text().toInt());
settings.setValue("analysis/offx", ui->lineX->text().toInt());
settings.setValue("analysis/offz", ui->lineZ->text().toInt());
}
static void loadLine(QSettings *s, QLineEdit *line, const char *key)
{
qlonglong x = line->text().toLongLong();
line->setText( QString::number(s->value(key, x).toLongLong()) );
}
void TabLocations::load(QSettings& settings)
{
loadLine(&settings, ui->lineN, "analysis/samplecnt");
loadLine(&settings, ui->lineA, "analysis/samplesep");
loadLine(&settings, ui->lineX, "analysis/offx");
loadLine(&settings, ui->lineZ, "analysis/offz");
QVariant mode = settings.value("analysis/samplemode", ui->comboSampling->currentData());
ui->comboSampling->setCurrentIndex(ui->comboSampling->findData(mode));
maxresults = settings.value("config/maxMatching", maxresults).toInt();
}
int TabLocations::warning(QString text, QMessageBox::StandardButtons buttons)
{
return warn(parent, text, buttons);
}
void TabLocations::onAnalysisItemDone(QTreeWidgetItem *item)
{
if (qbuf.size() + ui->treeWidget->topLevelItemCount() >= maxresults)
{
thread.stop = true;
}
qbuf.push_back(item);
quint64 ns = elapsed.nsecsElapsed();
if (ns > nextupdate)
{
nextupdate = ns + updt * 1e6;
QTimer::singleShot(updt, this, &TabLocations::onBufferTimeout);
}
}
void TabLocations::onAnalysisFinished()
{
timer.stop();
onBufferTimeout();
ui->pushExport->setEnabled(ui->treeWidget->topLevelItemCount() > 0);
ui->pushStart->setChecked(false);
ui->pushStart->setText(tr("Analyze"));
}
void TabLocations::onBufferTimeout()
{
uint64_t t = -elapsed.elapsed();
if (!qbuf.empty())
{
ui->treeWidget->setUpdatesEnabled(false);
ui->treeWidget->addTopLevelItems(qbuf);
ui->treeWidget->setUpdatesEnabled(true);
qbuf.clear();
onProgressTimeout();
}
QApplication::processEvents(); // force processing of events so we can time correctly
t += elapsed.elapsed();
if (8*t > updt)
updt = 4*t;
nextupdate = elapsed.nsecsElapsed() + 1e6 * updt;
}
void TabLocations::onProgressTimeout()
{
QString progress = QString::asprintf(" (%ld/%zu)", thread.idx.load(), thread.pos.size());
ui->pushStart->setText(tr("Stop") + progress);
}
void TabLocations::on_pushStart_clicked()
{
if (thread.isRunning())
{
thread.stop = true;
return;
}
updt = 20;
nextupdate = 0;
elapsed.start();
thread.pos.clear();
int mode = ui->comboSampling->currentData().toInt();
int a = ui->lineA->text().toInt();
uint64_t n = ui->lineN->text().toULongLong();
int x0 = ui->lineX->text().toInt();
int z0 = ui->lineZ->text().toInt();
if (a == 0)
return;
if (n > SAMPLES_MAX)
return;
WorldInfo wi;
parent->getSeed(&wi);
QVector<Condition> conds = parent->formCond->getConditions();
QString err = thread.set(wi, conds);
if (!err.isEmpty())
{
emit warning(err, QMessageBox::Ok);
return;
}
if (mode == SMODE_RADIAL_GRID)
{
struct P {
int x, z;
uint64_t rsq;
bool operator< (const P& x) const { return rsq < x.rsq; }
};
std::vector<P> v;
uint64_t rsqmax = (uint64_t) ceil(n / M_PI);
int64_t r = (int64_t) sqrt(rsqmax);
for (int64_t x = -r; x <= r; x++)
{
for (int64_t z = -r; z <= r; z++)
{
uint64_t rsq = (uint64_t)(x * x + z * z);
if (rsq <= rsqmax)
v.push_back(P{(int)x, (int)z, rsq});
}
}
std::sort(v.begin(), v.end());
for (uint64_t i = 0; i < n && i < v.size(); i++)
{
Pos p = { a*v[i].x + x0, a*v[i].z + z0};
thread.pos.push_back(p);
}
}
else if (mode == SMODE_SQUARE_SPIRAL)
{
int rx = 0;
int rz = 0;
int i = 0, dl = 1;
int dx = 1, dz = 0;
for (uint64_t j = 0; j < n; j++)
{
Pos p = { a*rx + x0, a*rz + z0 };
thread.pos.push_back(p);
rx += dx;
rz += dz;
if (++i == dl)
{
i = 0;
int tmp = dx;
dx = -dz;
dz = tmp;
if (dz == 0)
dl++;
}
}
}
else if (mode == SMODE_NORMAL)
{
thread_local RandGen rng;
std::normal_distribution<double> norm = std::normal_distribution<double>(0.0, 1.0);
for (uint64_t j = 0; j < n; j++)
{
int x = (int) round( a * norm(rng.mt) );
int z = (int) round( a * norm(rng.mt) );
Pos p = { x + x0, z + z0 };
thread.pos.push_back(p);
}
}
//ui->treeWidget->setSortingEnabled(false);
while (ui->treeWidget->topLevelItemCount() > 0)
delete ui->treeWidget->takeTopLevelItem(0);
ui->pushExport->setEnabled(false);
ui->pushStart->setChecked(true);
QString progress = QString::asprintf(" (0/%zu)", thread.pos.size());
ui->pushStart->setText(tr("Stop") + progress);
timer.start(250);
thread.start();
}
void TabLocations::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
{
(void) column;
QVariant dat;
dat = item->data(0, Qt::UserRole+0);
if (dat.isValid())
{
uint64_t seed = qvariant_cast<uint64_t>(dat);
dat = item->data(0, Qt::UserRole+1);
int dim = dat.isValid() ? dat.toInt() : DIM_UNDEF;
WorldInfo wi;
parent->getSeed(&wi);
wi.seed = seed;
parent->setSeed(wi, dim);
}
dat = item->data(0, Qt::UserRole+2);
if (dat.isValid())
{
Pos p = qvariant_cast<Pos>(dat);
parent->getMapView()->setView(p.x+0.5, p.z+0.5);
}
}
void TabLocations::on_pushExpand_clicked()
{
bool expand = false;
for (QTreeWidgetItemIterator it(ui->treeWidget); *it; ++it)
if (!(*it)->isExpanded())
expand = true;
if (expand)
ui->treeWidget->expandAll();
else
ui->treeWidget->collapseAll();
}
static
void csvline(QTextStream& stream, const QString& qte, const QString& sep, QStringList& cols)
{
if (qte.isEmpty())
{
for (QString& s : cols)
if (s.contains(sep))
s = "\"" + s + "\"";
}
stream << qte << cols.join(sep) << qte << "\n";
}
void TabLocations::on_pushExport_clicked()
{
QString fnam = QFileDialog::getSaveFileName(
this, tr("Export trigger analysis"), parent->prevdir, tr("Text files (*.txt *csv);;Any files (*)"));
if (fnam.isEmpty())
return;
QFileInfo finfo(fnam);
QFile file(fnam);
parent->prevdir = finfo.absolutePath();
if (!file.open(QIODevice::WriteOnly))
{
warn(parent, tr("Failed to open file for export:\n\"%1\"").arg(fnam));
return;
}
QString qte = parent->config.quote;
QString sep = parent->config.separator;
QTextStream stream(&file);
stream << "Sep=" + sep + "\n";
sep = qte + sep + qte;
QStringList header = { tr("condition"), tr("x"), tr("z") };
csvline(stream, qte, sep, header);
QTreeWidgetItemIterator it(ui->treeWidget);
for (; *it; ++it)
{
QTreeWidgetItem *item = *it;
QStringList cols;
for (int i = 0, n = item->columnCount(); i < n; i++)
{
QString s = item->text(i);
if (s == "-") s = "";
cols.append(s);
}
csvline(stream, qte, sep, cols);
}
}

78
src/tablocations.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef TABLOCATIONS_H
#define TABLOCATIONS_H
#include <QWidget>
#include <QThread>
#include <QTreeWidgetItem>
#include "mainwindow.h"
#include "search.h"
#include "world.h"
namespace Ui {
class TabLocations;
}
class AnalysisLocations : public QThread
{
Q_OBJECT
public:
explicit AnalysisLocations(QObject *parent = nullptr)
: QThread(parent), wi(),stop(),idx() {}
QString set(WorldInfo wi, const QVector<Condition>& conds);
virtual void run() override;
signals:
void itemDone(QTreeWidgetItem *item);
int warning(QString text, QMessageBox::StandardButtons buttons);
public:
WorldInfo wi;
ConditionTree condtree;
SearchThreadEnv env;
std::vector<Pos> pos;
std::atomic_bool stop;
std::atomic_long idx;
};
class TabLocations : public QWidget, public ISaveTab
{
Q_OBJECT
public:
explicit TabLocations(MainWindow *parent = nullptr);
~TabLocations();
virtual bool event(QEvent *e) override;
virtual void save(QSettings& settings) override;
virtual void load(QSettings& settings) override;
private slots:
int warning(QString text, QMessageBox::StandardButtons buttons);
void onAnalysisItemDone(QTreeWidgetItem *item);
void onAnalysisFinished();
void onBufferTimeout();
void onProgressTimeout();
void on_pushStart_clicked();
void on_pushExpand_clicked();
void on_pushExport_clicked();
void on_treeWidget_itemClicked(QTreeWidgetItem *item, int column);
private:
Ui::TabLocations *ui;
MainWindow *parent;
AnalysisLocations thread;
QTimer timer;
int maxresults;
QElapsedTimer elapsed;
uint64_t nextupdate;
uint64_t updt;
QList<QTreeWidgetItem*> qbuf;
};
#endif // TABLOCATIONS_H

175
src/tablocations.ui Normal file
View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TabLocations</class>
<widget class="QWidget" name="TabLocations">
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Centered on:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Sampling strategy:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;X:&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="4">
<widget class="QLineEdit" name="lineA">
<property name="text">
<string>512</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<widget class="QComboBox" name="comboSampling">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLineEdit" name="lineZ"/>
</item>
<item row="7" column="0" colspan="5">
<widget class="QTreeWidget" name="treeWidget">
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::NoDragDrop</enum>
</property>
<property name="indentation">
<number>12</number>
</property>
<property name="animated">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<attribute name="headerDefaultSectionSize">
<number>100</number>
</attribute>
<column>
<property name="text">
<string>condition</string>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
</column>
<column>
<property name="text">
<string>x</string>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
</column>
<column>
<property name="text">
<string>z</string>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
</column>
<column>
<property name="text">
<string>distance</string>
</property>
</column>
</widget>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="lineX"/>
</item>
<item row="8" column="0" colspan="5">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushExport">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Export...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushExpand">
<property name="text">
<string>Expand all</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushStart">
<property name="text">
<string>Analyze</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="3">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Z:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Spread (α):</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="4">
<widget class="QLineEdit" name="lineN">
<property name="text">
<string>1000</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Number of samples:</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -607,17 +607,14 @@ void TabStructures::on_pushExport_clicked()
void TabStructures::on_buttonFromVisible_clicked()
{
MapView *mapview = parent->getMapView();
qreal uiw = mapview->width() * mapview->getScale();
qreal uih = mapview->height() * mapview->getScale();
int bx0 = (int) floor(mapview->getX() - uiw/2);
int bz0 = (int) floor(mapview->getZ() - uih/2);
int bx1 = (int) ceil(mapview->getX() + uiw/2);
int bz1 = (int) ceil(mapview->getZ() + uih/2);
ui->lineX1->setText( QString::number(bx0) );
ui->lineZ1->setText( QString::number(bz0) );
ui->lineX2->setText( QString::number(bx1) );
ui->lineZ2->setText( QString::number(bz1) );
int x1, z1, x2, z2;
mapview->getVisible(&x1, &z1, &x2, &z2);
ui->lineX1->setText( QString::number(x1) );
ui->lineZ1->setText( QString::number(z1) );
ui->lineX2->setText( QString::number(x2) );
ui->lineZ2->setText( QString::number(z2) );
}
void TabStructures::on_tabWidget_currentChanged(int)

View File

@ -136,15 +136,12 @@ bool TabTriggers::event(QEvent *e)
return QWidget::event(e);
}
void TabTriggers::save(QSettings& settings)
void TabTriggers::save(QSettings&)
{
settings.setValue("analysis/seedsrc", ui->comboSeedSource->currentIndex());
}
void TabTriggers::load(QSettings& settings)
void TabTriggers::load(QSettings&)
{
int idx = settings.value("analysis/seedsrc", ui->comboSeedSource->currentIndex()).toInt();
ui->comboSeedSource->setCurrentIndex(idx);
}
int TabTriggers::warning(QString text, QMessageBox::StandardButtons buttons)
@ -251,7 +248,14 @@ void TabTriggers::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column)
void TabTriggers::on_pushExpand_clicked()
{
ui->treeWidget->expandAll();
bool expand = false;
for (QTreeWidgetItemIterator it(ui->treeWidget); *it; ++it)
if (!(*it)->isExpanded())
expand = true;
if (expand)
ui->treeWidget->expandAll();
else
ui->treeWidget->collapseAll();
}
static

View File

@ -83,7 +83,7 @@
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="labelDescription">
<property name="text">
<string>Analyze the search condition triggers.</string>
<string>Examine how the conditions are evaluated.</string>
</property>
</widget>
</item>

View File

@ -160,30 +160,24 @@ QString getBiomeDisplay(int mc, int id)
return name ? name : "";
}
RandGen::RandGen()
{
std::random_device rd;
if (rd.entropy())
mt = std::mt19937_64(rd());
else
mt = std::mt19937_64(time(0));
}
// get a random 64-bit integer
uint64_t getRnd64()
{
static QMutex mutex;
static std::random_device rd;
static std::mt19937_64 mt(rd());
static uint64_t x = (uint64_t) time(0);
static RandGen rng;
uint64_t ret = 0;
mutex.lock();
if (rd.entropy())
{
std::uniform_int_distribution<int64_t> d;
ret = d(mt);
}
else
{
const uint64_t c = 0xd6e8feb86659fd93ULL;
x ^= x >> 32;
x *= c;
x ^= x >> 32;
x *= c;
x ^= x >> 32;
ret = x;
}
std::uniform_int_distribution<uint64_t> d;
ret = d(rng.mt);
mutex.unlock();
return ret;
}

View File

@ -64,6 +64,12 @@ QString getStartPieceName(int stype, const StructureVariant *sv);
QString getBiomeDisplay(int mc, int id);
struct RandGen
{
RandGen();
std::mt19937_64 mt;
};
// get a random 64-bit integer
uint64_t getRnd64();

View File

@ -1224,6 +1224,8 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
painter.drawImage(rec, slimeimg);
}
// draw bounding boxes and shapes
painter.setPen(QPen(QColor(192, 0, 0, 160), 1));
if (showBB && blocks2pix >= 1.0 && qsinfo && dim == 0)
{
@ -1237,7 +1239,6 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
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));
@ -1245,6 +1246,29 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
}
}
for (Shape& s : shapes)
{
if (s.dim != dim)
continue;
qreal x1 = vw/2.0 + (s.p1.x - focusx) * blocks2pix;
qreal y1 = vh/2.0 + (s.p1.z - focusz) * blocks2pix;
qreal x2 = vw/2.0 + (s.p2.x - focusx) * blocks2pix;
qreal y2 = vh/2.0 + (s.p2.z - focusz) * blocks2pix;
qreal r = s.r * blocks2pix;
switch (s.type)
{
case Shape::RECT:
painter.drawRect(QRectF(x1, y1, x2-x1, y2-y1));
break;
case Shape::LINE:
painter.drawLine(QLineF(x1, y1, x2, y2));
break;
case Shape::CIRCLE:
painter.drawEllipse(QPointF(x1, y1), r, r);
break;
}
}
for (int sopt = D_DESERT; sopt < D_SPAWN; sopt++)
{
Level& l = lvs[sopt];

View File

@ -121,6 +121,14 @@ struct PosElement
Pos p;
};
struct Shape
{
enum { RECT, LINE, CIRCLE } type;
int dim;
int r;
Pos p1, p2;
};
class MapWorker : public QThread
{
Q_OBJECT
@ -206,6 +214,9 @@ public:
QImage slimeimg;
long slimex, slimez;
// shapes to overlay
std::vector<Shape> shapes;
// structure selection from mouse position
bool seldo;
qreal selx, selz;