Redesigned UI for search tab + moved settings storage

1) sections are now collapsable
2) merged conditions list, 48-bit list was 'replaced' by seed generator
3) added section for 48-bit seed generator:
3a) offers advanced controls
3b) better indication of how the search is managed
3c) includes basic preview of search space size
4) all settings in search-tab are saved in the 'session'
5) added cyclic autosave option for session data
6) session and protobase files moved to system provided config directory
7) config path changed - settings will be created anew
This commit is contained in:
Cubitect 2021-06-03 16:15:29 +02:00
parent a6a28916b9
commit b20ba50166
41 changed files with 3100 additions and 1485 deletions

View File

@ -15,7 +15,7 @@ AboutDialog::AboutDialog(QWidget *parent) :
if (VERS_PATCH >= 0)
text.replace("_PATCH_", QString::number(VERS_PATCH));
else
text.replace("_PATCH_", "dev");
text.replace("_PATCH_", "dev" + QString::number(-1-VERS_PATCH));
ui->label->setText(text);
}

View File

@ -4,8 +4,8 @@
#include <QDialog>
#define VERS_MAJOR 1
#define VERS_MINOR 5
#define VERS_PATCH 0
#define VERS_MINOR 6
#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)
@ -15,7 +15,9 @@ inline int cmpVers(int major, int minor, int patch)
if (s) return s;
s = (minor > VERS_MINOR) - (minor < VERS_MINOR);
if (s) return s;
s = (patch > VERS_PATCH) - (patch < VERS_PATCH);
int p0 = VERS_PATCH >= 0 ? 1000+VERS_PATCH : -VERS_PATCH;
int p1 = patch >= 0 ? 1000+patch : -patch;
s = (p1 > p0) - (p1 < p0);
return s;
}

126
collapsable.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "collapsable.h"
#include <QPropertyAnimation>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFont>
#include <QPushButton>
#include <QMessageBox>
Collapsable::Collapsable(QWidget *parent)
: QWidget(parent)
, animgroup(new QParallelAnimationGroup(this))
, toggleButton(new QToolButton(this))
, frameBar(new QFrame(this))
, content()
, contentHeight()
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding);
QFont font = toggleButton->font();
//font.setPixelSize(12);
font.setBold(true);
toggleButton->setFont(font);
toggleButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toggleButton->setArrowType(Qt::ArrowType::RightArrow);
toggleButton->setCheckable(true);
frameBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
frameBar->setFrameShape(QFrame::HLine);
QVBoxLayout *vbox = new QVBoxLayout();
layoutBar = new QHBoxLayout();
layoutBar->addWidget(toggleButton, Qt::AlignBottom);
layoutBar->addWidget(frameBar, Qt::AlignCenter);
layoutBar->setSpacing(5);
vbox->addLayout(layoutBar);
layoutContent = new QHBoxLayout();
layoutContent->setContentsMargins(20, 0, 0, 0);
vbox->addLayout(layoutContent);
vbox->setSizeConstraint(QLayout::SetMaximumSize);
vbox->setContentsMargins(0, 0, 0, 8);
vbox->setSpacing(0);
setLayout(vbox);
connect(toggleButton, &QToolButton::toggled, this, &Collapsable::toggle);
connect(animgroup, &QAbstractAnimation::finished, this, &Collapsable::finishAnimation);
}
void Collapsable::toggle(bool collapsed)
{
if (!content)
return;
if (collapsed)
{
content->setMinimumHeight(0);
content->setMaximumHeight(0);
toggleButton->setArrowType(Qt::ArrowType::DownArrow);
animgroup->setDirection(QAbstractAnimation::Forward);
}
else
{
contentHeight = content->size().height();
toggleButton->setArrowType(Qt::ArrowType::RightArrow);
animgroup->setDirection(QAbstractAnimation::Backward);
}
for (int i = 0, n = animgroup->animationCount(); i < n; i++)
{
QPropertyAnimation *anim;
anim = (QPropertyAnimation*) animgroup->animationAt(i);
anim->setStartValue(0);
anim->setEndValue(contentHeight);
anim->setDuration(150);
}
animgroup->start();
}
void Collapsable::finishAnimation()
{
if (toggleButton->isChecked())
{
content->setMinimumHeight(0);
content->setMaximumHeight(16777215);
}
}
void Collapsable::init(const QString& title, QWidget *widget, bool collapsed)
{
toggleButton->setText(title);
toggleButton->setChecked(!collapsed);
layoutContent->addWidget(widget);
contentHeight = widget->sizeHint().height();
content = widget;
animgroup->addAnimation(new QPropertyAnimation(content, "minimumHeight"));
animgroup->addAnimation(new QPropertyAnimation(content, "maximumHeight"));
if (collapsed)
{
content->setMinimumHeight(0);
content->setMaximumHeight(0);
}
}
void Collapsable::setInfo(const QString& title, const QString& text)
{
QPixmap pixmap = QPixmap(":/icons/info.png");
QPushButton *button = new QPushButton(pixmap, "", this);
button->setStyleSheet("border: none;");
button->setIconSize(pixmap.rect().size());
button->setToolTip("Show help");
connect(button, SIGNAL(clicked()), this, SLOT(showInfo()));
layoutBar->addWidget(button, Qt::AlignLeft);
infotitle = title;
infomsg = text;
}
void Collapsable::showInfo()
{
QMessageBox::information(this, infotitle, infomsg, QMessageBox::Ok);
}

36
collapsable.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef COLLAPSABLE_H
#define COLLAPSABLE_H
#include <QWidget>
#include <QParallelAnimationGroup>
#include <QToolButton>
#include <QFrame>
#include <QHBoxLayout>
class Collapsable : public QWidget
{
Q_OBJECT
public:
explicit Collapsable(QWidget *parent = nullptr);
void init(const QString& title, QWidget *widget, bool collapsed);
void setInfo(const QString& title, const QString& text);
public slots:
void toggle(bool collapsed);
void finishAnimation();
void showInfo();
public:
QParallelAnimationGroup* animgroup;
QToolButton* toggleButton;
QFrame* frameBar;
QWidget *content;
QHBoxLayout *layoutBar;
QHBoxLayout *layoutContent;
int contentHeight;
QString infotitle;
QString infomsg;
};
#endif // COLLAPSABLE_H

View File

@ -3,16 +3,6 @@
#include <QThread>
void Config::reset()
{
restoreSession = true;
smoothMotion = true;
seedsPerItem = 1024;
queueSize = QThread::idealThreadCount();
maxMatching = 65536;
}
ConfigDialog::ConfigDialog(QWidget *parent, Config *config) :
QDialog(parent),
ui(new Ui::ConfigDialog)
@ -32,16 +22,20 @@ ConfigDialog::~ConfigDialog()
void ConfigDialog::initSettings(Config *config)
{
ui->checkRestore->setChecked(config->restoreSession);
ui->checkSmooth->setChecked(config->smoothMotion);
ui->checkRestore->setChecked(config->restoreSession);
ui->checkAutosave->setChecked(config->autosaveCycle != 0);
if (config->autosaveCycle)
ui->spinAutosave->setValue(config->autosaveCycle);
ui->cboxItemSize->setCurrentText(QString::number(config->seedsPerItem));
ui->lineQueueSize->setText(QString::number(config->queueSize));
ui->lineMatching->setText(QString::number(config->maxMatching));
}
Config ConfigDialog::getConfig()
Config ConfigDialog::getSettings()
{
conf.restoreSession = ui->checkRestore->isChecked();
conf.autosaveCycle = ui->checkAutosave->isChecked() ? ui->spinAutosave->value() : 0;
conf.smoothMotion = ui->checkSmooth->isChecked();
conf.seedsPerItem = ui->cboxItemSize->currentText().toInt();
conf.queueSize = ui->lineQueueSize->text().toInt();

View File

@ -4,20 +4,13 @@
#include <QDialog>
#include <QAbstractButton>
#include "settings.h"
namespace Ui {
class ConfigDialog;
}
struct Config
{
bool restoreSession;
bool smoothMotion;
int seedsPerItem;
int queueSize;
int maxMatching;
void reset();
};
class ConfigDialog : public QDialog
{
@ -29,7 +22,7 @@ public:
void initSettings(Config *config);
Config getConfig();
Config getSettings();
private slots:
void on_buttonBox_clicked(QAbstractButton *button);

View File

@ -2,14 +2,6 @@
<ui version="4.0">
<class>ConfigDialog</class>
<widget class="QDialog" name="ConfigDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>411</width>
<height>228</height>
</rect>
</property>
<property name="windowTitle">
<string>Preferences</string>
</property>
@ -17,15 +9,40 @@
<iconset resource="icons.qrc">
<normaloff>:/icons/map.png</normaloff>:/icons/map.png</iconset>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="checkRestore">
<layout class="QGridLayout" name="gridLayout">
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Restore previous session at launch</string>
<string>Maximum number of matching seeds:</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<item row="8" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Size of search item queue:
(limits usable threads)</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Seeds per thread search item:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="checkSmooth">
<property name="toolTip">
<string>Simulate innertia for the map view</string>
@ -35,44 +52,42 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Seeds per thread search item:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="cboxItemSize"/>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Size of search item queue:
(limits usable threads)</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLineEdit" name="lineQueueSize"/>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_3">
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="checkRestore">
<property name="text">
<string>Maximum number of matching seeds:</string>
<string>Restore previous session at launch</string>
</property>
</widget>
</item>
<item row="9" column="1">
<item row="5" column="1">
<widget class="QComboBox" name="cboxItemSize"/>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="lineMatching"/>
</item>
<item row="12" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="4" column="0">
<widget class="QCheckBox" name="checkAutosave">
<property name="text">
<string>Autosave every:</string>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="spinAutosave">
<property name="suffix">
<string> min</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>120</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>

@ -1 +1 @@
Subproject commit ae227c67c283deb0c862e520df092267ac017228
Subproject commit 4ec179680619c2f031af08bece760bcd6b9c4b85

View File

@ -14,7 +14,7 @@ win32: {
}
QMAKE_CFLAGS = -fwrapv
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS -std=gnu++11
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS -std=gnu++11 -Wno-deprecated-copy -Wno-missing-field-initilizers
QMAKE_CXXFLAGS_RELEASE *= -O3
TARGET = cubiomes-viewer
@ -36,48 +36,60 @@ CONFIG += static
SOURCES += \
aboutdialog.cpp \
collapsable.cpp \
configdialog.cpp \
formconditions.cpp \
formgen48.cpp \
formsearchcontrol.cpp \
gotodialog.cpp \
protobasedialog.cpp \
filterdialog.cpp \
quadlistdialog.cpp \
mainwindow.cpp \
mapview.cpp \
quad.cpp \
search.cpp \
searchitem.cpp \
searchthread.cpp \
mainwindow.cpp \
main.cpp
HEADERS += \
configdialog.h \
collapsable.h \
cubiomes/finders.h \
cubiomes/generator.h \
cubiomes/javarnd.h \
cubiomes/layers.h \
cubiomes/util.h \
aboutdialog.h \
configdialog.h \
formconditions.h \
formgen48.h \
formsearchcontrol.h \
gotodialog.h \
protobasedialog.h \
filterdialog.h \
quadlistdialog.h \
mainwindow.h \
mapview.h \
quad.h \
cutil.h \
search.h \
searchitem.h \
searchthread.h \
seedtables.h
seedtables.h \
mainwindow.h \
settings.h
FORMS += \
aboutdialog.ui \
configdialog.ui \
formconditions.ui \
formgen48.ui \
formsearchcontrol.ui \
gotodialog.ui \
mainwindow.ui \
protobasedialog.ui \
filterdialog.ui \
quadlistdialog.ui
quadlistdialog.ui\
mainwindow.ui
RESOURCES += \
icons.qrc

View File

@ -1,6 +1,7 @@
#include "filterdialog.h"
#include "ui_filterdialog.h"
#include "mainwindow.h"
#include "cutil.h"
#include <QCheckBox>
@ -40,11 +41,11 @@ static QString getTip(int mc, int layer, int id)
}
FilterDialog::FilterDialog(MainWindow *parent, int mcversion, QListWidgetItem *item, Condition *initcond) :
QDialog(parent, Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint),
ui(new Ui::FilterDialog),
item(item),
mc(mcversion)
FilterDialog::FilterDialog(FormConditions *parent, int mcversion, QListWidgetItem *item, Condition *initcond)
: QDialog(parent, Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint)
, ui(new Ui::FilterDialog)
, item(item)
, mc(mcversion)
{
memset(&cond, 0, sizeof(cond));
ui->setupUi(this);

View File

@ -5,9 +5,12 @@
#include <QCheckBox>
#include <QSpinBox>
#include <QLineEdit>
#include <QListWidgetItem>
#include "mainwindow.h"
#include "search.h"
#include "formconditions.h"
class MainWindow;
namespace Ui {
class FilterDialog;
@ -53,14 +56,15 @@ public slots:
}
};
class FilterDialog : public QDialog
{
Q_OBJECT
public:
explicit FilterDialog(MainWindow *parent, int mc, QListWidgetItem *item = 0, Condition *initcond = 0);
~FilterDialog();
explicit FilterDialog(FormConditions *parent, int mc, QListWidgetItem *item = 0, Condition *initcond = 0);
virtual ~FilterDialog();
void updateMode();
void updateBiomeSelection();

276
formconditions.cpp Normal file
View File

@ -0,0 +1,276 @@
#include "formconditions.h"
#include "ui_formconditions.h"
#include "filterdialog.h"
#include "mainwindow.h"
#include <QMessageBox>
QDataStream& operator<<(QDataStream& out, const Condition& v)
{
out.writeRawData((const char*)&v, sizeof(Condition));
return out;
}
QDataStream& operator>>(QDataStream& in, Condition& v)
{
in.readRawData((char*)&v, sizeof(Condition));
return in;
}
FormConditions::FormConditions(MainWindow *parent)
: QWidget(parent)
, parent(parent)
, ui(new Ui::FormConditions)
{
ui->setupUi(this);
qRegisterMetaType< Condition >("Condition");
qRegisterMetaTypeStreamOperators< Condition >("Condition");
QFont mono = QFont("Monospace", 9);
mono.setStyleHint(QFont::TypeWriter);
ui->listConditionsFull->setFont(mono);
}
FormConditions::~FormConditions()
{
delete ui;
}
QVector<Condition> FormConditions::getConditions() const
{
QVector<Condition> conds;
for (int i = 0, ie = ui->listConditionsFull->count(); i < ie; i++)
conds.push_back(qvariant_cast<Condition>(ui->listConditionsFull->item(i)->data(Qt::UserRole)));
return conds;
}
void FormConditions::updateSensitivity()
{
int selectcnt = 0;
selectcnt += ui->listConditionsFull->selectedItems().size();
if (selectcnt == 0)
{
ui->buttonRemove->setEnabled(false);
ui->buttonEdit->setEnabled(false);
}
else if (selectcnt == 1)
{
ui->buttonRemove->setEnabled(true);
ui->buttonEdit->setEnabled(true);
}
else
{
ui->buttonRemove->setEnabled(true);
ui->buttonEdit->setEnabled(false);
}
}
int FormConditions::getIndex(int idx) const
{
const QVector<Condition> condvec = getConditions();
int cnt[100] = {};
for (const Condition& c : condvec)
if (c.save > 0 || c.save < 100)
cnt[c.save]++;
else return 0;
if (idx <= 0)
idx = 1;
if (cnt[idx] == 0)
return idx;
for (int i = 1; i < 100; i++)
if (cnt[i] == 0)
return i;
return 0;
}
QListWidgetItem *FormConditions::lockItem(QListWidgetItem *item)
{
QListWidgetItem *edit = item->clone();
item->setFlags(item->flags() & ~Qt::ItemIsSelectable);
item->setSelected(false);
item->setBackground(QColor(Qt::lightGray));
edit->setData(Qt::UserRole+1, (qulonglong)item);
return edit;
}
bool list_contains(QListWidget *list, QListWidgetItem *item)
{
if (!item)
return false;
int n = list->count();
for (int i = 0; i < n; i++)
if (list->item(i) == item)
return true;
return false;
}
// [ID] Condition Cnt Rel Area
void FormConditions::setItemCondition(QListWidget *list, QListWidgetItem *item, Condition *cond)
{
QListWidgetItem *target = (QListWidgetItem*) item->data(Qt::UserRole+1).toULongLong();
if (list_contains(list, target) && !(target->flags() & Qt::ItemIsSelectable))
{
item->setData(Qt::UserRole+1, (qulonglong)0);
*target = *item;
delete item;
item = target;
}
else
{
list->addItem(item);
cond->save = getIndex(cond->save);
}
const FilterInfo& ft = g_filterinfo.list[cond->type];
QString s = QString::asprintf("[%02d] %-28sx%-3d", cond->save, ft.name, cond->count);
if (cond->relative)
s += QString::asprintf("[%02d]+", cond->relative);
else
s += " ";
if (ft.coord)
s += QString::asprintf("(%d,%d)", cond->x1*ft.step, cond->z1*ft.step);
if (ft.area)
s += QString::asprintf(",(%d,%d)", (cond->x2+1)*ft.step-1, (cond->z2+1)*ft.step-1);
if (ft.cat == CAT_48)
item->setBackground(QColor(Qt::yellow));
else if (ft.cat == CAT_FULL)
item->setBackground(QColor(Qt::green));
item->setText(s);
item->setData(Qt::UserRole, QVariant::fromValue(*cond));
}
void FormConditions::editCondition(QListWidgetItem *item)
{
if (!(item->flags() & Qt::ItemIsSelectable))
return;
int mc = MC_1_16;
parent->getSeed(&mc, 0);
FilterDialog *dialog = new FilterDialog(this, mc, item, (Condition*)item->data(Qt::UserRole).data());
QObject::connect(dialog, SIGNAL(setCond(QListWidgetItem*,Condition)), this, SLOT(addItemCondition(QListWidgetItem*,Condition)), Qt::QueuedConnection);
dialog->show();
}
static void remove_selected(QListWidget *list)
{
QList<QListWidgetItem*> selected = list->selectedItems();
for (QListWidgetItem *item : selected)
{
delete list->takeItem(list->row(item));
}
}
void FormConditions::on_buttonRemoveAll_clicked()
{
ui->listConditionsFull->clear();
emit changed();
}
void FormConditions::on_buttonRemove_clicked()
{
remove_selected(ui->listConditionsFull);
emit changed();
}
void FormConditions::on_buttonEdit_clicked()
{
QListWidget *list = 0;
QListWidgetItem* edit = 0;
QList<QListWidgetItem*> selected;
list = ui->listConditionsFull;
selected = list->selectedItems();
if (!selected.empty())
edit = lockItem(selected.first());
if (edit)
editCondition(edit);
}
void FormConditions::on_buttonAddFilter_clicked()
{
int mc = MC_1_16;
parent->getSeed(&mc, 0);
FilterDialog *dialog = new FilterDialog(this, mc);
QObject::connect(dialog, SIGNAL(setCond(QListWidgetItem*,Condition)), this, SLOT(addItemCondition(QListWidgetItem*,Condition)), Qt::QueuedConnection);
dialog->show();
}
void FormConditions::on_listConditionsFull_itemDoubleClicked(QListWidgetItem *item)
{
editCondition(lockItem(item));
}
void FormConditions::on_listConditionsFull_itemSelectionChanged()
{
updateSensitivity();
}
void FormConditions::addItemCondition(QListWidgetItem *item, Condition cond)
{
const FilterInfo& ft = g_filterinfo.list[cond.type];
if (ft.cat == CAT_FULL)
{
if (!item)
item = new QListWidgetItem();
setItemCondition(ui->listConditionsFull, item, &cond);
}
else if (ft.cat == CAT_48 && item)
{
setItemCondition(ui->listConditionsFull, item, &cond);
}
else if (ft.cat == CAT_48 && item == NULL)
{
item = new QListWidgetItem();
setItemCondition(ui->listConditionsFull, item, &cond);
if (cond.type >= F_QH_IDEAL && cond.type <= F_QH_BARELY)
{
Condition cq = cond;
cq.type = F_HUT;
cq.x1 = -128; cq.z1 = -128;
cq.x2 = +128; cq.z2 = +128;
cq.relative = cond.save;
cq.save = cond.save+1;
cq.count = 4;
QListWidgetItem *item = new QListWidgetItem(ui->listConditionsFull, QListWidgetItem::UserType);
setItemCondition(ui->listConditionsFull, item, &cq);
}
else if (cond.type == F_QM_90 || cond.type == F_QM_95)
{
Condition cq = cond;
cq.type = F_MONUMENT;
cq.x1 = -160; cq.z1 = -160;
cq.x2 = +160; cq.z2 = +160;
cq.relative = cond.save;
cq.save = cond.save+1;
cq.count = 4;
QListWidgetItem *item = new QListWidgetItem(ui->listConditionsFull, QListWidgetItem::UserType);
setItemCondition(ui->listConditionsFull, item, &cq);
}
}
emit changed();
}
void FormConditions::on_listConditionsFull_indexesMoved(const QModelIndexList &)
{
emit changed();
}

55
formconditions.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef FORMCONDITIONS_H
#define FORMCONDITIONS_H
#include <QWidget>
#include <QListWidgetItem>
#include "searchthread.h"
namespace Ui {
class FormConditions;
}
class MainWindow;
Q_DECLARE_METATYPE(Condition)
class FormConditions : public QWidget
{
Q_OBJECT
public:
explicit FormConditions(MainWindow *parent);
~FormConditions();
QVector<Condition> getConditions() const;
void updateSensitivity();
int getIndex(int idx) const;
QListWidgetItem *lockItem(QListWidgetItem *item);
void setItemCondition(QListWidget *list, QListWidgetItem *item, Condition *cond);
void editCondition(QListWidgetItem *item);
signals:
void changed();
public slots:
void on_buttonRemoveAll_clicked();
void on_buttonRemove_clicked();
void on_buttonEdit_clicked();
void on_buttonAddFilter_clicked();
void on_listConditionsFull_itemDoubleClicked(QListWidgetItem *item);
void on_listConditionsFull_itemSelectionChanged();
void addItemCondition(QListWidgetItem *item, Condition cond);
private slots:
void on_listConditionsFull_indexesMoved(const QModelIndexList &indexes);
private:
MainWindow *parent;
Ui::FormConditions *ui;
};
#endif // FORMCONDITIONS_H

94
formconditions.ui Normal file
View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FormConditions</class>
<widget class="QWidget" name="FormConditions">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>420</width>
<height>221</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<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="1" column="0">
<widget class="QPushButton" name="buttonRemoveAll">
<property name="text">
<string>Remove all</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="buttonRemove">
<property name="text">
<string>Remove selection</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="buttonEdit">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="buttonAddFilter">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QListWidget" name="listConditionsFull">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="movement">
<enum>QListView::Snap</enum>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

352
formgen48.cpp Normal file
View File

@ -0,0 +1,352 @@
#include "formgen48.h"
#include "ui_formgen48.h"
#include "mainwindow.h"
#include "search.h"
#include "seedtables.h"
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
FormGen48::FormGen48(MainWindow *parent)
: QWidget(parent)
, parent(parent)
, ui(new Ui::FormGen48)
{
ui->setupUi(this);
QIntValidator *intval = new QIntValidator(this);
ui->lineSalt->setValidator(intval);
ui->lineEditX1->setValidator(intval);
ui->lineEditZ1->setValidator(intval);
ui->lineEditX2->setValidator(intval);
ui->lineEditZ2->setValidator(intval);
QFont mono = QFont("Monospace", 9);
mono.setStyleHint(QFont::TypeWriter);
ui->lineList48->setFont(mono);
cond.type = 0;
Gen48Settings defaults;
setSettings(defaults, true);
}
FormGen48::~FormGen48()
{
delete ui;
}
bool FormGen48::setList48(QString path, bool quiet)
{
bool ok = false;
if (!path.isEmpty())
{
QFileInfo finfo(path);
slist48path = path;
parent->prevdir = finfo.absolutePath();
int64_t *l = NULL;
int64_t len;
QByteArray ba = path.toLatin1();
l = loadSavedSeeds(ba.data(), &len);
if (l && len > 0)
{
slist48.assign(l, l+len);
free(l);
ui->lineList48->setText("[" + QString::number(len) + " seeds] " + finfo.baseName());
ok = true;
}
else
{
if (!quiet)
QMessageBox::warning(this, "Warning", "Failed to load seed list from file", QMessageBox::Ok);
ui->lineList48->setText("[no seeds!] " + finfo.baseName());
}
}
else
{
slist48path.clear();
ui->lineList48->setText("[none]");
slist48.clear();
}
emit changed();
return ok;
}
void FormGen48::setSettings(const Gen48Settings& gen48, bool quiet)
{
ui->comboMode->setCurrentIndex(gen48.mode);
ui->comboLow20->setCurrentIndex(gen48.qual);
ui->spinMonumentArea->setValue(gen48.qmarea);
ui->lineSalt->setText(QString::number(gen48.salt));
ui->lineEditX1->setText(QString::number(gen48.x1));
ui->lineEditZ1->setText(QString::number(gen48.z1));
ui->lineEditX2->setText(QString::number(gen48.x2));
ui->lineEditZ2->setText(QString::number(gen48.z2));
setList48(gen48.slist48path, quiet);
if (gen48.manualarea)
ui->radioManual->setChecked(true);
else
ui->radioAuto->setChecked(true);
on_comboMode_currentIndexChanged(gen48.mode);
}
Gen48Settings FormGen48::getSettings(bool resolveauto)
{
Gen48Settings s;
s.mode = ui->comboMode->currentIndex();
s.qual = ui->comboLow20->currentIndex();
s.qmarea = ui->spinMonumentArea->value();
s.salt = ui->lineSalt->text().toLongLong();
s.manualarea = ui->radioManual->isChecked();
s.x1 = ui->lineEditX1->text().toInt();
s.z1 = ui->lineEditZ1->text().toInt();
s.x2 = ui->lineEditX2->text().toInt();
s.z2 = ui->lineEditZ2->text().toInt();
s.slist48path = slist48path;
if (resolveauto)
{
if (s.mode == GEN48_AUTO)
{
bool isqh = cond.type >= F_QH_IDEAL && cond.type <= F_QH_BARELY;
bool isqm = cond.type >= F_QM_95 && cond.type <= F_QM_90;
if (isqh) s.mode = GEN48_QH;
if (isqm) s.mode = GEN48_QM;
}
}
return s;
}
uint64_t FormGen48::estimateSeedCnt()
{
const Gen48Settings& gen48 = getSettings(true);
uint64_t cnt = 0;
if (gen48.mode == GEN48_QH)
{
switch (gen48.qual)
{ // simply hardcoded number of seeds in each category
case IDEAL_SALTED: // falltrough
case IDEAL: cnt = 74474; break;
case CLASSIC: cnt = 107959; break;
case NORMAL: cnt = 293716; break;
case BARELY: cnt = 755745; break;
default: cnt = 0;
}
}
else if (gen48.mode == GEN48_QM)
{
cnt = 0;
for (int i = 0, n = sizeof(g_qm_90) / sizeof(int64_t); i < n; i++)
if (qmonumentQual(g_qm_90[i]) >= gen48.qmarea)
cnt++;
}
else if (gen48.mode == GEN48_LIST)
{
cnt = this->slist48.size();
}
else
{
cnt = MASK48+1;
}
if (gen48.mode != GEN48_NONE)
{
uint64_t w = gen48.x2 - gen48.x1 + 1;
uint64_t h = gen48.z2 - gen48.z1 + 1;
uint64_t n = w*h * cnt;
if (cnt > 0 && n < PRECOMPUTE48_BUFSIZ*sizeof(int64_t) && n / cnt == w*h)
cnt = n;
else
cnt = MASK48+1;
}
return cnt;
}
void FormGen48::updateCount()
{
uint64_t cnt = estimateSeedCnt();
if (cnt >= MASK48+1)
{
ui->labelCount->setText("all");
}
else
{
uint64_t total = cnt << 16;
ui->labelCount->setText(QString::asprintf("%" PRIu64 " * 65536 = %" PRIu64, cnt, total));
}
}
void FormGen48::updateAutoConditions(const QVector<Condition>& condlist)
{
cond.type = 0;
for (const Condition& c : condlist)
{
const FilterInfo& finfo = g_filterinfo.list[c.type];
if (finfo.cat == CAT_48)
{
cond = c;
break;
}
}
updateAutoUi();
}
void FormGen48::updateAutoUi()
{
QString modestr = "[Auto]";
bool isqh = cond.type >= F_QH_IDEAL && cond.type <= F_QH_BARELY;
bool isqm = cond.type >= F_QM_95 && cond.type <= F_QM_90;
if (isqh)
modestr += " (Quad-hut)";
else if (isqm)
modestr += " (Quad-monument)";
ui->comboMode->setItemText(GEN48_AUTO, modestr);
if (cond.type != 0)
{
if (ui->comboMode->currentIndex() == GEN48_AUTO)
{
ui->radioAuto->setChecked(true);
if (isqh)
ui->comboLow20->setCurrentIndex(cond.type - F_QH_IDEAL);
else if (isqm)
ui->spinMonumentArea->setValue((int) ceil( 58*58*4 * (cond.type == F_QM_95 ? 0.95 : 0.90) ));
}
if (ui->radioAuto->isChecked())
{
ui->lineEditX1->setText(QString::number(cond.x1));
ui->lineEditZ1->setText(QString::number(cond.z1));
ui->lineEditX2->setText(QString::number(cond.x2));
ui->lineEditZ2->setText(QString::number(cond.z2));
}
}
emit changed();
}
void FormGen48::setPathEnabled(bool enabled)
{
ui->buttonBrowse->setEnabled(enabled);
ui->lineList48->setEnabled(enabled);
ui->labelPath->setEnabled(enabled);
}
void FormGen48::setSaltEnabled(bool enabled)
{
ui->lineSalt->setEnabled(enabled);
ui->labelSalt->setEnabled(enabled);
}
void FormGen48::setAreaEnabled(bool enabled)
{
ui->labelTranspose->setEnabled(enabled);
ui->radioAuto->setEnabled(enabled);
ui->radioManual->setEnabled(enabled);
enabled &= ui->radioManual->isChecked();
ui->labelX1->setEnabled(enabled);
ui->labelZ1->setEnabled(enabled);
ui->labelX2->setEnabled(enabled);
ui->labelZ2->setEnabled(enabled);
ui->lineEditX1->setEnabled(enabled);
ui->lineEditZ1->setEnabled(enabled);
ui->lineEditX2->setEnabled(enabled);
ui->lineEditZ2->setEnabled(enabled);
}
void FormGen48::setQualEnabled(bool enabled)
{
ui->comboLow20->setEnabled(enabled);
ui->labelLow20->setEnabled(enabled);
}
void FormGen48::setQMEnabled(bool enabled)
{
ui->spinMonumentArea->setEnabled(enabled);
ui->labelQM->setEnabled(enabled);
}
void FormGen48::updateMode()
{
int mode = ui->comboMode->currentIndex();
int qual = ui->comboLow20->currentIndex();
if (mode == GEN48_AUTO)
{
updateAutoUi();
}
if (mode == GEN48_AUTO || mode == GEN48_NONE)
{
setAreaEnabled(false);
setPathEnabled(false);
setSaltEnabled(false);
setQualEnabled(false);
setQMEnabled(false);
}
else if (mode == GEN48_QH && qual == IDEAL_SALTED)
{
setAreaEnabled(true);
setPathEnabled(false);
setSaltEnabled(true);
setQualEnabled(true);
setQMEnabled(false);
}
else
{
setAreaEnabled(true);
setPathEnabled(mode == GEN48_LIST);
setSaltEnabled(mode == GEN48_LIST);
setQualEnabled(mode == GEN48_QH);
setQMEnabled(mode == GEN48_QM);
}
emit changed();
}
void FormGen48::on_comboMode_currentIndexChanged(int)
{
updateMode();
}
void FormGen48::on_comboLow20_currentIndexChanged(int)
{
updateMode();
}
void FormGen48::on_buttonBrowse_clicked()
{
QString fnam = QFileDialog::getOpenFileName(this, "Load seed list", parent->prevdir, "Text files (*.txt);;Any files (*)");
if (!fnam.isEmpty())
setList48(fnam, false);
}
void FormGen48::on_radioAuto_toggled()
{
setAreaEnabled(true);
emit changed();
}
void FormGen48::on_spinMonumentArea_editingFinished()
{
emit changed();
}
void FormGen48::on_lineSalt_editingFinished()
{
emit changed();
}

71
formgen48.h Normal file
View File

@ -0,0 +1,71 @@
#ifndef FORMGEN48_H
#define FORMGEN48_H
#include <QWidget>
#include <QThread>
#include "settings.h"
#include "search.h"
namespace Ui {
class FormGen48;
}
class MainWindow;
class FormGen48 : public QWidget
{
Q_OBJECT
public:
explicit FormGen48(MainWindow *parent);
~FormGen48();
void setSettings(const Gen48Settings& gen48, bool quiet);
Gen48Settings getSettings(bool resolveauto = false);
bool setList48(QString path, bool quiet);
const std::vector<int64_t>& getList48() { return slist48; }
uint64_t estimateSeedCnt();
void updateCount();
void updateAutoConditions(const QVector<Condition>& condlist);
void updateAutoUi();
signals:
void changed();
private:
void setPathEnabled(bool enabled);
void setSaltEnabled(bool enabled);
void setAreaEnabled(bool enabled);
void setQualEnabled(bool enabled);
void setQMEnabled(bool enabled);
void updateMode();
private slots:
void on_comboMode_currentIndexChanged(int idx);
void on_comboLow20_currentIndexChanged(int idx);
void on_buttonBrowse_clicked();
void on_radioAuto_toggled();
void on_spinMonumentArea_editingFinished();
void on_lineSalt_editingFinished();
private:
MainWindow *parent;
Ui::FormGen48 *ui;
// main condition for "auto" mode (updated when conditions change)
Condition cond;
QString slist48path;
std::vector<int64_t> slist48;
};
#endif // FORMGEN48_H

407
formgen48.ui Normal file
View File

@ -0,0 +1,407 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FormGen48</class>
<widget class="QWidget" name="FormGen48">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>428</width>
<height>251</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<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="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout_2">
<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="10" column="2" colspan="4">
<widget class="QLabel" name="labelCount">
<property name="text">
<string>0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="0" colspan="6">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<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>
<item row="0" column="0">
<widget class="QLabel" name="labelTranspose">
<property name="text">
<string>Transpose by regions (multiplied by x512):</string>
</property>
</widget>
</item>
<item row="0" column="1">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QRadioButton" name="radioAuto">
<property name="text">
<string>Auto</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QRadioButton" name="radioManual">
<property name="text">
<string>Manual</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="1" colspan="5">
<widget class="QComboBox" name="comboMode">
<item>
<property name="text">
<string>[Auto]</string>
</property>
</item>
<item>
<property name="text">
<string>Quad-feature</string>
</property>
</item>
<item>
<property name="text">
<string>Quad-monument</string>
</property>
</item>
<item>
<property name="text">
<string>Seed list</string>
</property>
</item>
<item>
<property name="text">
<string>[None] (All seeds)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1" colspan="5">
<widget class="QComboBox" name="comboLow20">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property>
<item>
<property name="text">
<string>Quad-hut (ideal)</string>
</property>
</item>
<item>
<property name="text">
<string>Quad-hut (classic)</string>
</property>
</item>
<item>
<property name="text">
<string>Quad-hut (normal)</string>
</property>
</item>
<item>
<property name="text">
<string>Quad-hut (barely)</string>
</property>
</item>
<item>
<property name="text">
<string>Quad-feature (ideal, custom salt)</string>
</property>
</item>
</widget>
</item>
<item row="5" column="1" colspan="5">
<widget class="QLineEdit" name="lineSalt">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelMode">
<property name="text">
<string>Generator mode:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelPath">
<property name="toolTip">
<string>Use a custom seed list as source for 48-bit seed candidates</string>
</property>
<property name="text">
<string>Load 48-bit seed list:</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="5">
<widget class="QSpinBox" name="spinMonumentArea">
<property name="minimum">
<number>12115</number>
</property>
<property name="maximum">
<number>13028</number>
</property>
<property name="value">
<number>13028</number>
</property>
</widget>
</item>
<item row="11" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1" colspan="4">
<widget class="QLineEdit" name="lineList48">
<property name="font">
<font>
<family>Monospace</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelLow20">
<property name="toolTip">
<string>Selects a set of values for the lower 20-bits of the seed, corresponding to quad-feature constellations
Applies only to feature-structures of region-size = 32 and chunk-gap = 8, in particular swamp-huts</string>
</property>
<property name="text">
<string>Restrict lower bits:</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="2">
<widget class="QLabel" name="labelSpace">
<property name="text">
<string>Seeds in search space:</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="6">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labelX1">
<property name="toolTip">
<string>Lower bound (inclusive)</string>
</property>
<property name="text">
<string>X&lt;sub&gt;1&lt;/sub&gt;=</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditX1">
<property name="toolTip">
<string>Lower bound (inclusive)</string>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelZ1">
<property name="toolTip">
<string>Lower bound (inclusive)</string>
</property>
<property name="text">
<string>Z&lt;sub&gt;1&lt;/sub&gt;=</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditZ1">
<property name="toolTip">
<string>Lower bound (inclusive)</string>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="labelX2">
<property name="toolTip">
<string>Upper bound (inclusive)</string>
</property>
<property name="text">
<string>X&lt;sub&gt;2&lt;/sub&gt;=</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditX2">
<property name="toolTip">
<string>Upper bound (inclusive)</string>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelZ2">
<property name="toolTip">
<string>Upper bound (inclusive)</string>
</property>
<property name="text">
<string>Z&lt;sub&gt;2&lt;/sub&gt;=</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditZ2">
<property name="toolTip">
<string>Upper bound (inclusive)</string>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelSalt">
<property name="toolTip">
<string>Value (such as a structure salt) added to the 48-bit seeds</string>
</property>
<property name="text">
<string>Add structure salt:</string>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QPushButton" name="buttonBrowse">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelQM">
<property name="toolTip">
<string>Number of planar spawning spaces inside monuments that are within 128 blocks of a center position
(i.e. this is a measure quality, out of 4*58*58)</string>
</property>
<property name="text">
<string>Min. monument area:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

457
formsearchcontrol.cpp Normal file
View File

@ -0,0 +1,457 @@
#include "formsearchcontrol.h"
#include "ui_formsearchcontrol.h"
#include "mainwindow.h"
#include "search.h"
#include <QMessageBox>
#include <QMenu>
#include <QAction>
#include <QClipboard>
#include <QFileDialog>
#include <QMessageBox>
FormSearchControl::FormSearchControl(MainWindow *parent)
: QWidget(parent)
, parent(parent)
, ui(new Ui::FormSearchControl)
, sthread(this)
, stimer()
, slist64path()
, slist64()
{
ui->setupUi(this);
QFont mono = QFont("Monospace", 9);
mono.setStyleHint(QFont::TypeWriter);
ui->listResults->setFont(mono);
ui->progressBar->setFont(mono);
//connect(&sthread, &SearchThread::results, this, &MainWindow::searchResultsAdd, Qt::BlockingQueuedConnection);
connect(&sthread, &SearchThread::progress, this, &FormSearchControl::searchProgress, Qt::QueuedConnection);
connect(&sthread, &SearchThread::searchFinish, this, &FormSearchControl::searchFinish, Qt::QueuedConnection);
connect(&stimer, &QTimer::timeout, this, QOverload<>::of(&FormSearchControl::resultTimeout));
stimer.start(500);
searchProgressReset();
ui->spinThreads->setMaximum(QThread::idealThreadCount());
ui->spinThreads->setValue(QThread::idealThreadCount());
searchLockUi(false);
}
FormSearchControl::~FormSearchControl()
{
stimer.stop();
sthread.stop(); // tell search to stop at next convenience
sthread.quit(); // tell the event loop to exit
sthread.wait(); // wait for search to finish
delete ui;
}
QVector<int64_t> FormSearchControl::getResults()
{
int n = ui->listResults->rowCount();
QVector<int64_t> results = QVector<int64_t>(n);
for (int i = 0; i < n; i++)
{
results[i] = ui->listResults->item(i, 0)->data(Qt::UserRole).toLongLong();
}
return results;
}
SearchConfig FormSearchControl::getSearchConfig()
{
SearchConfig s;
s.searchmode = ui->comboSearchType->currentIndex();
s.threads = ui->spinThreads->value();
s.slist64path = slist64path;
s.startseed = ui->lineStart->text().toLongLong();
s.stoponres = ui->checkStop->isChecked();
return s;
}
bool FormSearchControl::setSearchConfig(SearchConfig s, bool quiet)
{
bool ok = true;
if (s.searchmode >= SEARCH_INC && s.searchmode <= SEARCH_LIST)
ui->comboSearchType->setCurrentIndex(s.searchmode);
else
ok = false;
ui->spinThreads->setValue(s.threads);
ui->lineStart->setText(QString::asprintf("%" PRId64, s.startseed));
ui->checkStop->setChecked(s.stoponres);
return ok && setList64(s.slist64path, quiet);
}
bool FormSearchControl::isbusy()
{
return ui->buttonStart->isChecked() || sthread.isRunning();
}
bool FormSearchControl::setList64(QString path, bool quiet)
{
if (!path.isEmpty())
{
QFileInfo finfo(path);
parent->prevdir = finfo.absolutePath();
slist64path = finfo.fileName();
int64_t *l = NULL;
int64_t len;
QByteArray ba = path.toLatin1();
l = loadSavedSeeds(ba.data(), &len);
if (l && len > 0)
{
slist64.assign(l, l+len);
searchProgress(0, len, l[0]);
free(l);
return true;
}
else
{
if (!quiet)
QMessageBox::warning(this, "Warning", "Failed to load seed list from file", QMessageBox::Ok);
}
}
return false;
}
void FormSearchControl::searchLockUi(bool lock)
{
if (lock)
{
ui->comboSearchType->setEnabled(false);
ui->spinThreads->setEnabled(false);
}
else
{
ui->buttonStart->setText("Start search");
ui->buttonStart->setIcon(QIcon(":/icons/search.png"));
ui->buttonStart->setChecked(false);
ui->buttonStart->setEnabled(true);
ui->comboSearchType->setEnabled(true);
ui->spinThreads->setEnabled(true);
}
emit searchStatusChanged(lock);
}
void FormSearchControl::setSearchMode(int mode)
{
ui->comboSearchType->setCurrentIndex(mode);
if (mode == SEARCH_LIST)
{
on_buttonLoadList_clicked();
}
else
{
slist64.clear();
slist64path.clear();
}
}
void FormSearchControl::on_buttonClear_clicked()
{
ui->listResults->clearContents();
ui->listResults->setRowCount(0);
searchProgressReset();
}
void FormSearchControl::on_buttonStart_clicked()
{
if (ui->buttonStart->isChecked())
{
int mc = MC_1_16;
parent->getSeed(&mc, NULL);
const Config& config = parent->config;
const QVector<Condition>& condvec = parent->formCond->getConditions();
int64_t sstart = (int64_t) ui->lineStart->text().toLongLong();
int searchtype = ui->comboSearchType->currentIndex();
int threads = ui->spinThreads->value();
int ok = true;
if (condvec.empty())
{
QMessageBox::warning(this, "Warning", "Please define some constraints using the \"Add\" button.", QMessageBox::Ok);
ok = false;
}
if (searchtype == SEARCH_LIST && slist64.empty())
{
QMessageBox::warning(this, "Warning", "No seed list file selected.", QMessageBox::Ok);
ok = false;
}
if (sthread.isRunning())
{
QMessageBox::warning(this, "Warning", "Search is still running.", QMessageBox::Ok);
ok = false;
}
if (ok)
{
Gen48Settings gen48 = parent->formGen48->getSettings(true);
// the search can either use a full list or a 48-bit list
if (searchtype == SEARCH_LIST)
slist = slist64;
else if (gen48.mode == GEN48_LIST)
slist = parent->formGen48->getList48();
else
slist.clear();
ok = sthread.set(parent, searchtype, threads, gen48, slist, sstart, mc, condvec, config.seedsPerItem, config.queueSize);
}
if (ok)
{
ui->lineStart->setText(QString::asprintf("%" PRId64, sstart));
ui->buttonStart->setText("Abort search");
ui->buttonStart->setIcon(QIcon(":/icons/cancel.png"));
sthread.start();
searchLockUi(true);
}
else
{
ui->buttonStart->setChecked(false);
}
}
else
{
sthread.stop(); // tell search to stop at next convenience
//sthread.quit(); // tell the event loop to exit
//sthread.wait(); // wait for search to finish
ui->buttonStart->setText("Start search");
ui->buttonStart->setIcon(QIcon(":/icons/search.png"));
ui->buttonStart->setChecked(false);
// disable until finish
ui->buttonStart->setEnabled(false);
}
update();
}
void FormSearchControl::on_buttonLoadList_clicked()
{
QString fnam = QFileDialog::getOpenFileName(this, "Load seed list", parent->prevdir, "Text files (*.txt);;Any files (*)");
setList64(fnam, false);
}
void FormSearchControl::on_listResults_itemSelectionChanged()
{
int row = ui->listResults->currentRow();
if (row >= 0 && row < ui->listResults->rowCount())
{
int64_t s = ui->listResults->item(row, 0)->data(Qt::UserRole).toLongLong();
emit selectedSeedChanged(s);
}
}
void FormSearchControl::on_listResults_customContextMenuRequested(const QPoint &pos)
{
QMenu menu(this);
QAction *actremove = menu.addAction(QIcon::fromTheme("list-remove"), "Remove selected seed", this, &FormSearchControl::removeCurrent);
actremove->setEnabled(!ui->listResults->selectedItems().empty());
QAction *actcopy = menu.addAction(QIcon::fromTheme("edit-copy"), "Copy list to clipboard", this, &FormSearchControl::copyResults);
actcopy->setEnabled(ui->listResults->rowCount() > 0);
int n = pasteList(true);
QAction *actpaste = menu.addAction(QIcon::fromTheme("edit-paste"), QString::asprintf("Paste %d seeds from clipboard", n), this, &FormSearchControl::pasteResults);
actpaste->setEnabled(n > 0);
menu.exec(ui->listResults->mapToGlobal(pos));
}
void FormSearchControl::on_buttonSearchHelp_clicked()
{
const char* msg =
"<html><head/><body><p>The <span style=\" font-weight:600;\">incremental</span> "
"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.</p>"
"<p>With <span style=\" font-weight:600;\">48-bit family blocks</span> the search looks for suitable "
"48-bit seeds first and parallelizes the search through the upper 16-bits. "
"This type of search is best suited for exhaustive searches and for many types of structure restrictions.</p>"
"<p>Load a <span style=\" font-weight:600;\">seed list from a file</span> to search through an existing set of seeds. "
"The seeds should be in decimal ASCII text, separated by newline characters. "
"You can browse for a file using the &quot;...&quot; button. (The seed generator is ignored with this option.)"
"</p></body></html>"
;
QMessageBox::information(this, "Help: search types", msg, QMessageBox::Ok);
}
void FormSearchControl::on_comboSearchType_currentIndexChanged(int index)
{
ui->buttonLoadList->setEnabled(index == SEARCH_LIST);
}
void FormSearchControl::pasteResults()
{
pasteList(false);
}
int FormSearchControl::pasteList(bool dummy)
{
QClipboard *clipboard = QGuiApplication::clipboard();
QStringList slist = clipboard->text().split('\n');
QVector<int64_t> seeds;
for (QString s : slist)
{
s = s.trimmed();
if (s.isEmpty())
continue;
bool ok = true;
int64_t seed = s.toLongLong(&ok);
if (!ok)
return 0;
seeds.push_back(seed);
}
if (!seeds.empty())
{
return searchResultsAdd(seeds, dummy);
}
return 0;
}
int FormSearchControl::searchResultsAdd(QVector<int64_t> seeds, bool countonly)
{
const Config& config = parent->config;
int ns = ui->listResults->rowCount();
int n = ns;
if (n >= config.maxMatching)
return 0;
if (seeds.size() + n > config.maxMatching)
seeds.resize(config.maxMatching - n);
if (seeds.empty())
return 0;
QSet<int64_t> current;
current.reserve(n + seeds.size());
for (int i = 0; i < n; i++)
{
int64_t seed = ui->listResults->item(i, 0)->data(Qt::UserRole).toLongLong();
current.insert(seed);
}
ui->listResults->setSortingEnabled(false);
for (int64_t s : seeds)
{
if (current.contains(s))
continue;
if (countonly)
{
n++;
continue;
}
current.insert(s);
QTableWidgetItem* s48item = new QTableWidgetItem();
QTableWidgetItem* seeditem = new QTableWidgetItem();
s48item->setData(Qt::UserRole, QVariant::fromValue(s));
s48item->setText(QString::asprintf("%012llx|%04x",
(qulonglong)(s & MASK48), (uint)(s >> 48) & 0xffff));
seeditem->setData(Qt::DisplayRole, QVariant::fromValue(s));
ui->listResults->insertRow(n);
ui->listResults->setItem(n, 0, s48item);
ui->listResults->setItem(n, 1, seeditem);
n++;
}
ui->listResults->setSortingEnabled(true);
if (countonly == false && n >= config.maxMatching)
{
sthread.stop();
QString msg = QString::asprintf("Maximum number of results reached (%d).", config.maxMatching);
QMessageBox::warning(this, "Warning", msg, QMessageBox::Ok);
}
int addcnt = n - ns;
if (ui->checkStop->isChecked() && addcnt)
{
sthread.reqstop = true;
sthread.pool.clear();
}
if (addcnt)
emit resultsAdded(addcnt);
return addcnt;
}
void FormSearchControl::searchProgressReset()
{
uint64_t cnt = parent->formGen48->estimateSeedCnt();
if (cnt > MASK48)
cnt = ~(uint64_t)0;
else
cnt <<= 16;
QString fmt = QString::asprintf("0 / %" PRIu64 " (0.00%%)", cnt);
if (!slist64path.isEmpty() && ui->comboSearchType->currentIndex() == SEARCH_LIST)
fmt = slist64path + ": " + fmt;
ui->lineStart->setText("0");
ui->progressBar->setValue(0);
ui->progressBar->setFormat(fmt);
}
void FormSearchControl::searchProgress(uint64_t last, uint64_t end, int64_t seed)
{
// if (sthread.itemgen.searchtype == SEARCH_BLOCKS)
// seed &= MASK48;
ui->lineStart->setText(QString::asprintf("%" PRId64, seed));
if (end)
{
int v = (int) floor(10000 * (double)last / end);
ui->progressBar->setValue(v);
QString fmt = QString::asprintf(
"%" PRIu64 " / %" PRIu64 " (%d.%02d%%)", last, end, v / 100, v % 100);
if (!slist64path.isEmpty() && ui->comboSearchType->currentIndex() == SEARCH_LIST)
fmt = slist64path + ": " + fmt;
ui->progressBar->setFormat(fmt);
}
}
void FormSearchControl::searchFinish()
{
if (!sthread.abort)
{
searchProgress(0, 0, sthread.itemgen.seed);
}
if (sthread.itemgen.isdone)
{
ui->progressBar->setValue(10000);
ui->progressBar->setFormat(QString::asprintf("Done"));
}
searchLockUi(false);
}
void FormSearchControl::resultTimeout()
{
update();
}
void FormSearchControl::removeCurrent()
{
int row = ui->listResults->currentRow();
if (row >= 0)
ui->listResults->removeRow(row);
}
void FormSearchControl::copyResults()
{
QString text;
int n = ui->listResults->rowCount();
for (int i = 0; i < n; i++)
{
int64_t seed = ui->listResults->item(i, 0)->data(Qt::UserRole).toLongLong();
text += QString::asprintf("%" PRId64 "\n", seed);
}
QClipboard *clipboard = QGuiApplication::clipboard();
clipboard->setText(text);
}

78
formsearchcontrol.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef FORMSEARCHCONTROL_H
#define FORMSEARCHCONTROL_H
#include <QWidget>
#include <QTimer>
#include "searchthread.h"
#include "protobasedialog.h"
#include "settings.h"
namespace Ui {
class FormSearchControl;
}
class MainWindow;
class FormSearchControl : public QWidget
{
Q_OBJECT
public:
explicit FormSearchControl(MainWindow *parent);
~FormSearchControl();
QVector<int64_t> getResults();
SearchConfig getSearchConfig();
bool setSearchConfig(SearchConfig s, bool quiet);
bool isbusy();
bool setList64(QString path, bool quiet);
void searchLockUi(bool lock);
void setSearchMode(int mode);
signals:
void selectedSeedChanged(int64_t seed);
void searchStatusChanged(bool running);
void resultsAdded(int cnt);
public slots:
void on_buttonClear_clicked();
void on_buttonStart_clicked();
void on_buttonLoadList_clicked();
void on_listResults_itemSelectionChanged();
void on_listResults_customContextMenuRequested(const QPoint& pos);
void on_buttonSearchHelp_clicked();
void on_comboSearchType_currentIndexChanged(int index);
void pasteResults();
int pasteList(bool dummy);
int searchResultsAdd(QVector<int64_t> seeds, bool countonly);
void searchProgressReset();
void searchProgress(uint64_t last, uint64_t end, int64_t seed);
void searchFinish();
void resultTimeout();
void removeCurrent();
void copyResults();
private:
MainWindow *parent;
Ui::FormSearchControl *ui;
SearchThread sthread;
QTimer stimer;
// the seed list option is not stored in a widget but is loaded with the "..." button
QString slist64path;
std::vector<int64_t> slist64;
// buffer for seed candidates while search is running
std::vector<int64_t> slist;
};
#endif // FORMSEARCHCONTROL_H

286
formsearchcontrol.ui Normal file
View File

@ -0,0 +1,286 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FormSearchControl</class>
<widget class="QWidget" name="FormSearchControl">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>420</width>
<height>315</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<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="QTableWidget" name="listResults">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>160</number>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>20</number>
</attribute>
<column>
<property name="text">
<string>Hex (Low-48 | Top-16)</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
<column>
<property name="text">
<string>Seed</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="4">
<widget class="QPushButton" name="buttonLoadList">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QLineEdit" name="lineStart">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Threads:</string>
</property>
</widget>
</item>
<item row="1" column="4" colspan="3">
<widget class="QCheckBox" name="checkStop">
<property name="toolTip">
<string>stop as soon as the next set of matching seeds is found</string>
</property>
<property name="text">
<string>Stop on results</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;searching algorithm&lt;/p&gt;&lt;p&gt;incremental: best for non-exhaustive biome searches&lt;/p&gt;&lt;p&gt;48-bit family blocks: best for searches with strong structure restrictions&lt;/p&gt;&lt;p&gt;seed list from file...: load and search through a pre-computed list of seed&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Search:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="buttonSearchHelp">
<property name="maximumSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">border: none;</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/info.png</normaloff>:/icons/info.png</iconset>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Seed:</string>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QSpinBox" name="spinThreads">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>16</number>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QComboBox" name="comboSearchType">
<item>
<property name="text">
<string>incremental</string>
</property>
</item>
<item>
<property name="text">
<string>48-bit family blocks</string>
</property>
</item>
<item>
<property name="text">
<string>seed list from a file...</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0" colspan="7">
<widget class="QProgressBar" name="progressBar">
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="toolTip">
<string>Progress within the set of all 48-bit seeds.</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="format">
<string>0</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="7">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="buttonClear">
<property name="text">
<string>Clear results</string>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/clear.png</normaloff>:/icons/clear.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonStart">
<property name="text">
<string>Start search</string>
</property>
<property name="icon">
<iconset resource="icons.qrc">
<normaloff>:/icons/search.png</normaloff>:/icons/search.png</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -41,5 +41,11 @@
<file>icons/slime_d.png</file>
<file>icons/slime.png</file>
<file>icons/grid_d.png</file>
<file>icons/splitter_v.png</file>
<file>icons/splitter_h.png</file>
<file>icons/search.png</file>
<file>icons/cancel.png</file>
<file>icons/clear.png</file>
<file>icons/info.png</file>
</qresource>
</RCC>

BIN
icons/cancel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
icons/clear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
icons/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
icons/search.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
icons/splitter_h.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
icons/splitter_v.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because it is too large Load Diff

View File

@ -16,8 +16,10 @@
#include <atomic>
#include "searchthread.h"
#include "protobasedialog.h"
#include "configdialog.h"
#include "formconditions.h"
#include "formgen48.h"
#include "formsearchcontrol.h"
namespace Ui {
class MainWindow;
@ -26,10 +28,11 @@ class MainWindow;
Q_DECLARE_METATYPE(int64_t)
Q_DECLARE_METATYPE(uint64_t)
Q_DECLARE_METATYPE(Pos)
Q_DECLARE_METATYPE(Condition)
Q_DECLARE_METATYPE(Config)
class MapView;
class Gen48Settings;
class ProtoBaseDialog;
class MainWindow : public QMainWindow
{
@ -43,7 +46,6 @@ public:
bool getSeed(int *mc, int64_t *seed, bool applyrand = true);
bool setSeed(int mc, int64_t seed);
QVector<Condition> getConditions() const;
MapView *getMapView();
protected:
@ -51,60 +53,30 @@ protected:
void loadSettings();
bool saveProgress(QString fnam, bool quiet = false);
bool loadProgress(QString fnam, bool quiet = false);
QListWidgetItem *lockItem(QListWidgetItem *item);
void setItemCondition(QListWidget *list, QListWidgetItem *item, Condition *cond);
void editCondition(QListWidgetItem *item);
void updateMapSeed();
void updateSensitivity();
int getIndex(int idx) const;
public slots:
void warning(QString title, QString text);
void mapGoto(qreal x, qreal z, qreal scale);
void openProtobaseMsg(QString path);
void closeProtobaseMsg();
int searchResultsAdd(QVector<int64_t> seeds, bool countonly);
private slots:
void on_comboBoxMC_currentIndexChanged(int a);
void on_seedEdit_editingFinished();
void on_seedEdit_textChanged(const QString &arg1);
void on_buttonRemoveAll_clicked();
void on_buttonRemove_clicked();
void on_buttonEdit_clicked();
void on_buttonAddFilter_clicked();
void on_listConditions48_itemDoubleClicked(QListWidgetItem *item);
void on_listConditionsFull_itemDoubleClicked(QListWidgetItem *item);
void on_listConditions48_itemSelectionChanged();
void on_listConditionsFull_itemSelectionChanged();
void on_buttonClear_clicked();
void on_buttonStart_clicked();
void on_listResults_itemSelectionChanged();
void on_listResults_customContextMenuRequested(const QPoint &pos);
void on_buttonInfo_clicked();
void on_buttonSearchHelp_clicked();
void on_actionSave_triggered();
void on_actionLoad_triggered();
void on_actionQuit_triggered();
void on_actionCopy_triggered();
void on_actionPaste_triggered();
void on_actionPreferences_triggered();
void on_actionGo_to_triggered();
void on_actionScan_seed_for_Quad_Huts_triggered();
void on_actionOpen_shadow_seed_triggered();
void on_actionAbout_triggered();
void on_actionSearch_seed_list_triggered();
void on_actionSearch_full_seed_space_triggered();
void on_comboSearchType_currentIndexChanged(int index);
void on_buttonLoadList_clicked();
void on_actionCopy_triggered();
void on_actionPaste_triggered();
void on_mapView_customContextMenuRequested(const QPoint &pos);
@ -115,30 +87,30 @@ private slots:
void on_treeAnalysis_itemDoubleClicked(QTreeWidgetItem *item);
void on_buttonExport_clicked();
// internal events
void on_actionSearch_seed_list_triggered();
void on_actionSearch_full_seed_space_triggered();
// internal events
void onAutosaveTimeout();
void onActionMapToggled(int stype, bool a);
void addItemCondition(QListWidgetItem *item, Condition cond);
void searchProgress(uint64_t last, uint64_t end, int64_t seed);
void searchFinish();
void resultTimeout();
void removeCurrent();
void copyResults();
void pasteResults();
int pasteList(bool dummy = false);
void onConditionsChanged();
void onGen48Changed();
void onSelectedSeedChanged(int64_t seed);
void onSearchStatusChanged(bool running);
void copyCoord();
public:
Ui::MainWindow *ui;
QVector<QAction*> saction;
SearchThread sthread;
QTimer stimer;
ProtoBaseDialog *protodialog;
QString prevdir;
QString slistfnam;
std::vector<int64_t> slist64;
FormConditions *formCond;
FormGen48 *formGen48;
FormSearchControl *formControl;
Config config;
QString prevdir;
QTimer autosaveTimer;
QVector<QAction*> saction;
ProtoBaseDialog *protodialog;
};
#endif // MAINWINDOW_H

View File

@ -23,7 +23,14 @@
!checked { background-color:rgb(240, 240, 240); }
border: 2px solid #8f8f91;
border-radius:3px;
}</string>
}
QSplitter::handle:horizontal {
image: url(:/icons/splitter_h.png);
}
QSplitter::handle:vertical {
image: url(:/icons/splitter_v.png);
}
</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QGridLayout" name="gridLayout_6">
@ -161,373 +168,110 @@
<number>0</number>
</property>
<widget class="QWidget" name="tabSearch">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Search</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_5">
<layout class="QGridLayout" name="gridLayout">
<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="QSplitter" name="splitterSearch">
<property name="orientation">
<enum>Qt::Vertical</enum>
<widget class="QScrollArea" name="scrollArea">
<property name="minimumSize">
<size>
<width>480</width>
<height>0</height>
</size>
</property>
<widget class="QGroupBox" name="groupConstraints">
<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">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1227</width>
<height>697</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Constraints</string>
<property name="minimumSize">
<size>
<width>440</width>
<height>0</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>4</number>
<number>0</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item row="3" column="0">
<widget class="QPushButton" name="buttonInfo">
<property name="maximumSize">
<size>
<width>20</width>
<height>16777215</height>
</size>
<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>
</property>
<property name="text">
<string>?</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="buttonRemoveAll">
<property name="text">
<string>Remove all</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="5">
<widget class="QSplitter" name="splitterConditions">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QListWidget" name="listConditions48">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="toolTip">
<string>Conditions for the 48-bit seed generator</string>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="movement">
<enum>QListView::Snap</enum>
<widget class="Collapsable" name="collapseConstraints" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QListWidget" name="listConditionsFull">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
<widget class="Collapsable" name="collapseGen48" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="toolTip">
<string>Conditions with full biome dependency</string>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="movement">
<enum>QListView::Snap</enum>
</widget>
<widget class="Collapsable" name="collapseControl" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="buttonEdit">
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="buttonRemove">
<property name="text">
<string>Remove selection</string>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QPushButton" name="buttonAddFilter">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupMatching">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Matching seeds</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
<item row="0" column="0">
<widget class="QTableWidget" name="listResults">
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>160</number>
</attribute>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>20</number>
</attribute>
<column>
<property name="text">
<string>Hex (Low-48 | Top-16)</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
<column>
<property name="text">
<string>Seed</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
</widget>
</item>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="4">
<widget class="QPushButton" name="buttonLoadList">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QComboBox" name="comboSearchType">
<item>
<property name="text">
<string>incremental</string>
</property>
</item>
<item>
<property name="text">
<string>48-bit family blocks</string>
</property>
</item>
<item>
<property name="text">
<string>seed list from a file...</string>
</property>
</item>
</widget>
</item>
<item row="0" column="6">
<widget class="QSpinBox" name="spinThreads">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>16</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;searching algorithm&lt;/p&gt;&lt;p&gt;incremental: best for non-exhaustive biome searches&lt;/p&gt;&lt;p&gt;48-bit family blocks: best for searches with strong structure restrictions&lt;/p&gt;&lt;p&gt;seed list from file...: load and search through a pre-computed list of seed&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Search:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="7">
<widget class="QProgressBar" name="progressBar">
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="toolTip">
<string>Progress within the set of all 48-bit seeds.</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="format">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="buttonSearchHelp">
<property name="maximumSize">
<size>
<width>20</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>?</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Seed:</string>
</property>
</widget>
</item>
<item row="1" column="4" colspan="3">
<widget class="QCheckBox" name="checkStop">
<property name="toolTip">
<string>stop as soon as the next set of matching seeds is found</string>
</property>
<property name="text">
<string>Stop on results</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Threads:</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QLineEdit" name="lineStart">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="7">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="buttonClear">
<property name="text">
<string>Clear results</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonStart">
<property name="text">
<string>Start search</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
@ -923,6 +667,12 @@ QToolButton:checked {
<header>mapview.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>Collapsable</class>
<extends>QWidget</extends>
<header>collapsable.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="icons.qrc"/>

View File

@ -59,17 +59,6 @@ void getStructs(std::vector<VarPos> *out, const StructureConfig sconf,
}
}
std::vector<VarPos> *Quad::addStruct(const StructureConfig sconf)
{
LayerStack g;
setupGenerator(&g, mc);
int x0 = ti*blocks, x1 = (ti+1)*blocks;
int z0 = tj*blocks, z1 = (tj+1)*blocks;
std::vector<VarPos>* st = new std::vector<VarPos>();
getStructs(st, sconf, &g, mc, seed, x0, z0, x1, z1);
return st;
}
void Quad::run()
{
@ -108,7 +97,16 @@ void Quad::run()
}
if (structureType >= 0)
{
spos = addStruct(getConfig(structureType, mc));
LayerStack g;
setupGenerator(&g, mc);
int x0 = ti*blocks, x1 = (ti+1)*blocks;
int z0 = tj*blocks, z1 = (tj+1)*blocks;
std::vector<VarPos>* st = new std::vector<VarPos>();
StructureConfig sconf;
if (getConfig(structureType, mc, &sconf))
getStructs(st, sconf, &g, mc, seed, x0, z0, x1, z1);
spos = st;
}
}
done = true;

46
quad.h
View File

@ -29,6 +29,50 @@ enum {
STRUCT_NUM
};
inline const char *mapopt2str(int opt)
{
switch (opt)
{
case D_GRID: return "grid";
case D_SLIME: return "slime";
case D_DESERT: return "desert";
case D_JUNGLE: return "jungle";
case D_IGLOO: return "igloo";
case D_HUT: return "hut";
case D_VILLAGE: return "village";
case D_MANSION: return "mansion";
case D_MONUMENT: return "monument";
case D_RUINS: return "ruins";
case D_SHIPWRECK: return "shipwreck";
case D_TREASURE: return "treasure";
case D_OUTPOST: return "outpost";
case D_PORTAL: return "portal";
case D_SPAWN: return "spawn";
case D_STRONGHOLD: return "stronghold";
default: return "";
}
}
inline int str2mapopt(const char *s)
{
if (!strcmp(s, "grid")) return D_GRID;
if (!strcmp(s, "slime")) return D_SLIME;
if (!strcmp(s, "desert")) return D_DESERT;
if (!strcmp(s, "jungle")) return D_JUNGLE;
if (!strcmp(s, "igloo")) return D_IGLOO;
if (!strcmp(s, "hut")) return D_HUT;
if (!strcmp(s, "village")) return D_VILLAGE;
if (!strcmp(s, "mansion")) return D_MANSION;
if (!strcmp(s, "monument")) return D_MONUMENT;
if (!strcmp(s, "ruins")) return D_RUINS;
if (!strcmp(s, "shipwreck")) return D_SHIPWRECK;
if (!strcmp(s, "treasure")) return D_TREASURE;
if (!strcmp(s, "outpost")) return D_OUTPOST;
if (!strcmp(s, "portal")) return D_PORTAL;
if (!strcmp(s, "spawn")) return D_SPAWN;
if (!strcmp(s, "stronghold")) return D_STRONGHOLD;
return D_NONE;
}
struct Level;
@ -47,8 +91,6 @@ public:
Quad(const Level* l, int i, int j);
~Quad();
std::vector<VarPos> *addStruct(const StructureConfig sconf);
void run();
int mc;

View File

@ -1,6 +1,7 @@
#include "quadlistdialog.h"
#include "ui_quadlistdialog.h"
#include "mainwindow.h"
#include "mapview.h"
#include "cutil.h"
#include "seedtables.h"
@ -10,7 +11,6 @@
#include <QMenu>
QuadListDialog::QuadListDialog(MainWindow *mainwindow)
: QDialog(mainwindow)
, ui(new Ui::QuadListDialog)

View File

@ -2,7 +2,8 @@
#define QUADLISTDIALOG_H
#include <QDialog>
#include "mainwindow.h"
class MainWindow;
namespace Ui {
class QuadListDialog;

View File

@ -9,175 +9,6 @@
extern MainWindow *gMainWindowInstance;
int check(int64_t s48, void *data)
{
const StructureConfig sconf = *(const StructureConfig*) data;
return isQuadBase(sconf, s48 - sconf.salt, 128);
}
/* Loads a seed list for a filter type from disk, or generates it if neccessary.
* @mc mincreaft version
* @ftyp filter type
* @qb output seed base list
* @qbn output length of seed base list
* @dyn list was dynamically allocated and requires a free
* @sconf structure configuration used for the bases
*/
static void genSeedBases(int mc, int ftyp, const int64_t **qb, int64_t *qbn,
int *dyn, StructureConfig *sconf)
{
char fnam[128];
const char *lbstr = NULL;
const int64_t *lbset = NULL;
int64_t lbcnt = 0;
int64_t *dqb = NULL;
*qb = NULL;
*qbn = 0;
*dyn = 0;
switch (ftyp)
{
case F_QH_IDEAL:
lbstr = "ideal";
lbset = low20QuadIdeal;
lbcnt = sizeof(low20QuadIdeal) / sizeof(int64_t);
goto L_QH_ANY;
case F_QH_CLASSIC:
lbstr = "cassic";
lbset = low20QuadClassic;
lbcnt = sizeof(low20QuadClassic) / sizeof(int64_t);
goto L_QH_ANY;
case F_QH_NORMAL:
lbstr = "normal";
lbset = low20QuadHutNormal;
lbcnt = sizeof(low20QuadHutNormal) / sizeof(int64_t);
goto L_QH_ANY;
case F_QH_BARELY:
lbstr = "barely";
lbset = low20QuadHutBarely;
lbcnt = sizeof(low20QuadHutBarely) / sizeof(int64_t);
goto L_QH_ANY;
L_QH_ANY:
snprintf(fnam, sizeof(fnam), "protobases/quad_%s.txt", lbstr);
*sconf = mc <= MC_1_12 ? SWAMP_HUT_CONFIG_112 : SWAMP_HUT_CONFIG;
if ((dqb = loadSavedSeeds(fnam, qbn)) == NULL)
{
QMetaObject::invokeMethod(gMainWindowInstance, "openProtobaseMsg", Qt::QueuedConnection, Q_ARG(QString, QString(fnam)));
int threads = QThread::idealThreadCount();
int err = searchAll48(&dqb, qbn, fnam, threads, lbset, lbcnt, 20, check, sconf);
QMetaObject::invokeMethod(gMainWindowInstance, "closeProtobaseMsg", Qt::BlockingQueuedConnection);
if (err)
{
QMetaObject::invokeMethod(
gMainWindowInstance, "warning", Qt::BlockingQueuedConnection,
Q_ARG(QString, QString("Warning")),
Q_ARG(QString, QString("Failed to generate protobases.")));
return;
}
}
if (dqb)
{
// convert protobases to proper bases by subtracting the salt
for (int64_t i = 0; i < (*qbn); i++)
dqb[i] -= sconf->salt;
*qb = (const int64_t*)dqb;
*dyn = 1;
}
break;
case F_QM_95:
*qb = g_qm_95;
*qbn = sizeof(g_qm_95) / sizeof(int64_t);
*sconf = MONUMENT_CONFIG;
*dyn = 0;
break;
case F_QM_90:
*qb = g_qm_90;
*qbn = sizeof(g_qm_90) / sizeof(int64_t);
*sconf = MONUMENT_CONFIG;
*dyn = 0;
break;
}
}
/* Produces a list of seed bases from precomputed lists, provided all candidates fit into a buffer.
*
* @param list output list
* @param mc mincraft version
* @param cond conditions
* @param ccnt number of conditions
* @param bufmax maximum allowed buffer size
*/
void getCandidates(std::vector<int64_t>& list, int mc, const Condition *cond, int ccnt, int64_t bufmax)
{
int ci;
for (ci = 0; ci < ccnt; ci++)
{
if (cond[ci].relative)
continue;
int64_t q, qbn = 0, *p;
const int64_t *qb = NULL;
StructureConfig sconf;
int dyn;
int i, j;
genSeedBases(mc, cond[ci].type, &qb, &qbn, &dyn, &sconf);
if (!qb)
continue;
int x = cond[ci].x1;
int z = cond[ci].z1;
int w = cond[ci].x2 - x + 1;
int h = cond[ci].z2 - z + 1;
// does the set of candidates for this condition fit in memory?
if (qbn * w*h * 4 * (int64_t)sizeof(int64_t) >= bufmax)
goto L_next_cond;
try {
list.resize(qbn * w*h);
} catch (...) {
goto L_next_cond;
}
p = list.data();
for (j = 0; j < h; j++)
{
for (i = 0; i < w; i++)
{
for (q = 0; q < qbn; q++)
{
*p++ = moveStructure(qb[q], x+i, z+j);
}
}
}
L_next_cond:
if (dyn && qb)
free((void*)qb);
if (!list.empty())
break;
}
if (!list.empty())
{
std::sort(list.begin(), list.end());
auto last = std::unique(list.begin(), list.end());
list.erase(last, list.end());
}
}
static bool intersectLineLine(double ax1, double az1, double ax2, double az2, double bx1, double bz1, double bx2, double bz2)
{
double ax = ax2 - ax1, az = az2 - az1;
@ -243,6 +74,13 @@ int testCond(StructPos *spos, int64_t seed, const Condition *cond, int mc, Layer
Pos p[128];
StructPos *sout = spos + cond->save;
const FilterInfo& finfo = g_filterinfo.list[cond->type];
if (finfo.stype > 0)
{
if (!getConfig(finfo.stype, mc, &sconf))
return 0;
}
switch (cond->type)
{
@ -250,7 +88,6 @@ int testCond(StructPos *spos, int64_t seed, const Condition *cond, int mc, Layer
case F_QH_CLASSIC:
case F_QH_NORMAL:
case F_QH_BARELY:
sconf = mc <= MC_1_12 ? SWAMP_HUT_CONFIG_112 : SWAMP_HUT_CONFIG;
qual = cond->type;
if (cond->relative)
@ -293,7 +130,6 @@ int testCond(StructPos *spos, int64_t seed, const Condition *cond, int mc, Layer
case F_QM_95: qual = 58*58*4 * 95 / 100; goto L_qm_any;
case F_QM_90: qual = 58*58*4 * 90 / 100;
L_qm_any:
sconf = MONUMENT_CONFIG;
if (cond->relative)
{
@ -333,19 +169,19 @@ L_qm_any:
return 0;
case F_DESERT: sconf = getConfig(Desert_Pyramid, mc); goto L_struct_any;
case F_HUT: sconf = getConfig(Swamp_Hut, mc); goto L_struct_any;
case F_JUNGLE: sconf = getConfig(Jungle_Pyramid, mc); goto L_struct_any;
case F_IGLOO: sconf = getConfig(Igloo, mc); goto L_struct_any;
case F_MONUMENT: sconf = getConfig(Monument, mc); goto L_struct_any;
case F_VILLAGE: sconf = getConfig(Village, mc); goto L_struct_any;
case F_OUTPOST: sconf = getConfig(Outpost, mc); goto L_struct_any;
case F_MANSION: sconf = getConfig(Mansion, mc); goto L_struct_any;
case F_RUINS: sconf = getConfig(Ocean_Ruin, mc); goto L_struct_any;
case F_SHIPWRECK: sconf = getConfig(Shipwreck, mc); goto L_struct_any;
case F_PORTAL: sconf = getConfig(Ruined_Portal, mc); goto L_struct_any;
case F_DESERT:
case F_HUT:
case F_JUNGLE:
case F_IGLOO:
case F_MONUMENT:
case F_VILLAGE:
case F_OUTPOST:
case F_MANSION:
case F_RUINS:
case F_SHIPWRECK:
case F_TREASURE:
case F_PORTAL:
L_struct_any:
x1 = cond->x1;
z1 = cond->z1;
x2 = cond->x2;
@ -365,6 +201,13 @@ L_struct_any:
rx2 = x2 >> 9;
rz2 = z2 >> 9;
}
else if (sconf.regionSize == 1)
{
rx1 = x1 >> 4;
rz1 = z1 >> 4;
rx2 = x2 >> 4;
rz2 = z2 >> 4;
}
else
{
rx1 = (x1 / (sconf.regionSize << 4)) - (x1 < 0);
@ -407,54 +250,6 @@ L_struct_any:
}
return 0;
case F_TREASURE:
sconf = TREASURE_CONFIG;
x1 = cond->x1;
z1 = cond->z1;
x2 = cond->x2;
z2 = cond->z2;
if (cond->relative)
{
x1 += spos[cond->relative].cx;
z1 += spos[cond->relative].cz;
x2 += spos[cond->relative].cx;
z2 += spos[cond->relative].cz;
}
rx1 = x1 >> 4;
rz1 = z1 >> 4;
rx2 = x2 >> 4;
rz2 = z2 >> 4;
sout->cx = xt = 0;
sout->cz = zt = 0;
qual = 0;
for (int rz = rz1; rz <= rz2; rz++)
{
for (int rx = rx1; rx <= rx2; rx++)
{
pc = { (rx << 4) + 9, (rz << 4) + 9 };
if (pc.x < x1 || pc.x > x2 || pc.z < z1 || pc.z > z2)
continue;
if (!isTreasureChunk(seed, rx, rz))
continue;
if (g && !isViableStructurePos(sconf.structType, mc, g, seed, pc.x, pc.z))
continue;
xt += pc.x;
zt += pc.z;
if (++qual >= cond->count)
{
sout->sconf = sconf;
sout->cx = xt / qual;
sout->cz = zt / qual;
return 1;
}
}
}
return 0;
case F_SPAWN:
// TODO: warn if spawn is used for relative positioning
sout->cx = 0;
@ -608,12 +403,14 @@ L_struct_any:
}
return 0;
case F_BIOME: s = 0; qual = L_VORONOI_ZOOM_1; goto L_biome_filter_any;
case F_BIOME_4_RIVER: s = 2; qual = L_RIVER_MIX_4; goto L_biome_filter_any;
case F_BIOME_16_SHORE: s = 4; qual = L_SHORE_16; goto L_biome_filter_any;
case F_BIOME_64_RARE: s = 6; qual = L_RARE_BIOME_64; goto L_biome_filter_any;
case F_BIOME_256_BIOME: s = 8; qual = L_BIOME_256; goto L_biome_filter_any;
case F_BIOME_256_OTEMP: s = 8; qual = L13_OCEAN_TEMP_256; goto L_biome_filter_any;
// biome filters reference specific layers
// MAYBE: options for layers in different versions?
case F_BIOME: s = 0; goto L_biome_filter_any;
case F_BIOME_4_RIVER: s = 2; goto L_biome_filter_any;
case F_BIOME_16_SHORE: s = 4; goto L_biome_filter_any;
case F_BIOME_64_RARE: s = 6; goto L_biome_filter_any;
case F_BIOME_256_BIOME: s = 8; goto L_biome_filter_any;
case F_BIOME_256_OTEMP: s = 8; goto L_biome_filter_any;
L_biome_filter_any:
if (cond->relative)
@ -634,7 +431,7 @@ L_biome_filter_any:
sout->cz = ((rz1 + rz2) << s) >> 1;
if (!g)
{
if (qual != L13_OCEAN_TEMP_256)
if (finfo.layer != L_OCEAN_TEMP_256)
return 1;
if (mc < MC_1_13)
return 0;
@ -648,8 +445,8 @@ L_biome_filter_any:
{
int w = rx2-rx1+1;
int h = rz2-rz1+1;
int *area = allocCache(&g->layers[qual], w, h);
if (checkForBiomes(g, qual, area, seed, rx1, rz1, w, h, cond->bfilter, 0) > 0)
int *area = allocCache(&g->layers[finfo.layer], w, h);
if (checkForBiomes(g, finfo.layer, area, seed, rx1, rz1, w, h, cond->bfilter, 0) > 0)
{
// check biome exclusion
uint64_t b = 0, bm = 0;

View File

@ -3,9 +3,10 @@
#include "cubiomes/finders.h"
#include <vector>
#include <atomic>
#define PRECOMPUTE48_BUFSIZ ((int64_t)1 << 30)
enum
{
CAT_NONE,
@ -19,6 +20,7 @@ struct FilterInfo
bool coord; // requires coordinate entry
bool area; // requires area entry
int layer; // associated generator layer
int stype; // structure type
int step; // coordinate multiplier
int count; //
int mcmin; // minimum version
@ -69,14 +71,14 @@ static const struct FilterList
FilterList() : list{}
{
list[F_SELECT] = FilterInfo{
CAT_NONE, 0, 0, 0, 0, 0, MC_1_0,
CAT_NONE, 0, 0, 0, 0, 0, 0, MC_1_0,
NULL,
"",
""
};
list[F_QH_IDEAL] = FilterInfo{
CAT_48, 1, 1, 0, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
":icons/quad.png",
"Quad-hut (ideal)",
"The lower 48-bits provide potential for four swamp huts in "
@ -84,7 +86,7 @@ static const struct FilterList
};
list[F_QH_CLASSIC] = FilterInfo{
CAT_48, 1, 1, 0, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
":icons/quad.png",
"Quad-hut (classic)",
"The lower 48-bits provide potential for four swamp huts in "
@ -94,7 +96,7 @@ static const struct FilterList
};
list[F_QH_NORMAL] = FilterInfo{
CAT_48, 1, 1, 0, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
":icons/quad.png",
"Quad-hut (normal)",
"The lower 48-bits provide potential for four swamp huts in "
@ -104,7 +106,7 @@ static const struct FilterList
};
list[F_QH_BARELY] = FilterInfo{
CAT_48, 1, 1, 0, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
":icons/quad.png",
"Quad-hut (barely)",
"The lower 48-bits provide potential for four swamp huts in "
@ -113,7 +115,7 @@ static const struct FilterList
};
list[F_QM_95] = FilterInfo{
CAT_48, 1, 1, 0, 512, 0, MC_1_8,
CAT_48, 1, 1, 0, Monument, 512, 0, MC_1_8,
":icons/quad.png",
"Quad-ocean-monument (>95%)",
"The lower 48-bits provide potential for 95% of the area of "
@ -122,7 +124,7 @@ static const struct FilterList
};
list[F_QM_90] = FilterInfo{
CAT_48, 1, 1, 0, 512, 0, MC_1_8,
CAT_48, 1, 1, 0, Monument, 512, 0, MC_1_8,
":icons/quad.png",
"Quad-ocean-monument (>90%)",
"The lower 48-bits provide potential for 90% of the area of "
@ -131,7 +133,7 @@ static const struct FilterList
};
list[F_BIOME] = FilterInfo{
CAT_FULL, 1, 1, L_VORONOI_1, 1, 0, MC_1_0,
CAT_FULL, 1, 1, L_VORONOI_1, 0, 1, 0, MC_1_0,
":icons/map.png",
"Biome filter 1:1",
"Only seeds with the included (+) biomes in the specified area and "
@ -139,7 +141,7 @@ static const struct FilterList
};
list[F_BIOME_4_RIVER] = FilterInfo{
CAT_FULL, 1, 1, L_RIVER_MIX_4, 4, 0, MC_1_0,
CAT_FULL, 1, 1, L_RIVER_MIX_4, 0, 4, 0, MC_1_0,
":icons/map.png",
"Biome filter 1:4 RIVER",
"Only seeds with the included (+) biomes in the specified area and "
@ -148,7 +150,7 @@ static const struct FilterList
};
list[F_BIOME_16_SHORE] = FilterInfo{
CAT_FULL, 1, 1, L_SHORE_16, 16, 0, MC_1_0,
CAT_FULL, 1, 1, L_SHORE_16, 0, 16, 0, MC_1_0,
":icons/map.png",
"Biome filter 1:16 SHORE",
"Only seeds with the included (+) biomes in the specified area and "
@ -157,7 +159,7 @@ static const struct FilterList
};
list[F_BIOME_64_RARE] = FilterInfo{
CAT_FULL, 1, 1, L_SUNFLOWER_64, 64, 0, MC_1_7,
CAT_FULL, 1, 1, L_SUNFLOWER_64, 0, 64, 0, MC_1_7,
":icons/map.png",
"Biome filter 1:64 RARE",
"Only seeds with the included (+) biomes in the specified area and "
@ -166,7 +168,7 @@ static const struct FilterList
};
list[F_BIOME_256_BIOME] = FilterInfo{
CAT_FULL, 1, 1, L_BIOME_256, 256, 0, MC_1_0,
CAT_FULL, 1, 1, L_BIOME_256, 0, 256, 0, MC_1_0,
":icons/map.png",
"Biome filter 1:256 BIOME",
"Only seeds with the included (+) biomes in the specified area and "
@ -175,7 +177,7 @@ static const struct FilterList
};
list[F_BIOME_256_OTEMP] = FilterInfo{
CAT_48, 1, 1, L13_OCEAN_TEMP_256, 256, 0, MC_1_13,
CAT_48, 1, 1, L_OCEAN_TEMP_256, 0, 256, 0, MC_1_13,
":icons/map.png",
"Biome filter 1:256 O.TEMP",
"Only seeds with the included (+) biomes in the specified area and "
@ -185,112 +187,112 @@ static const struct FilterList
};
list[F_TEMPS] = FilterInfo{
CAT_FULL, 1, 1, 0, 1024, 0, MC_1_7,
CAT_FULL, 1, 1, 0, 0, 1024, 0, MC_1_7,
":icons/tempcat.png",
"Temperature categories",
"Checks that the area has a minimum of all the required temperature categories."
};
list[F_SLIME] = FilterInfo{
CAT_FULL, 1, 1, 0, 16, 1, MC_1_0,
CAT_FULL, 1, 1, 0, 0, 16, 1, MC_1_0,
":icons/slime.png",
"Slime chunk",
""
};
list[F_SPAWN] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 0, MC_1_0,
CAT_FULL, 1, 1, 0, 0, 1, 0, MC_1_0,
":icons/spawn.png",
"Spawn",
""
};
list[F_STRONGHOLD] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_0,
CAT_FULL, 1, 1, 0, 0, 1, 1, MC_1_0,
":icons/stronghold.png",
"Stronghold",
""
};
list[F_DESERT] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_3,
CAT_FULL, 1, 1, 0, Desert_Pyramid, 1, 1, MC_1_3,
":icons/desert.png",
"Desert pyramid",
""
};
list[F_JUNGLE] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_3,
CAT_FULL, 1, 1, 0, Jungle_Pyramid, 1, 1, MC_1_3,
":icons/jungle.png",
"Jungle temple",
""
};
list[F_HUT] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_4,
CAT_FULL, 1, 1, 0, Swamp_Hut, 1, 1, MC_1_4,
":icons/hut.png",
"Swamp hut",
""
};
list[F_IGLOO] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_9,
CAT_FULL, 1, 1, 0, Igloo, 1, 1, MC_1_9,
":icons/igloo.png",
"Igloo",
""
};
list[F_MONUMENT] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_8,
CAT_FULL, 1, 1, 0, Monument, 1, 1, MC_1_8,
":icons/monument.png",
"Ocean monument",
""
};
list[F_VILLAGE] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_0,
CAT_FULL, 1, 1, 0, Village, 1, 1, MC_1_0,
":icons/village.png",
"Village",
""
};
list[F_OUTPOST] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_14,
CAT_FULL, 1, 1, 0, Outpost, 1, 1, MC_1_14,
":icons/outpost.png",
"Pillager outpost",
""
};
list[F_MANSION] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_11,
CAT_FULL, 1, 1, 0, Mansion, 1, 1, MC_1_11,
":icons/mansion.png",
"Woodland mansion",
""
};
list[F_TREASURE] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_13,
CAT_FULL, 1, 1, 0, Treasure, 1, 1, MC_1_13,
":icons/treasure.png",
"Buried treasure",
""
};
list[F_RUINS] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_13,
CAT_FULL, 1, 1, 0, Ocean_Ruin, 1, 1, MC_1_13,
":icons/ruins.png",
"Ocean ruins",
""
};
list[F_SHIPWRECK] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_13,
CAT_FULL, 1, 1, 0, Shipwreck, 1, 1, MC_1_13,
":icons/shipwreck.png",
"Shipwreck",
""
};
list[F_PORTAL] = FilterInfo{
CAT_FULL, 1, 1, 0, 1, 1, MC_1_16,
CAT_FULL, 1, 1, 0, Ruined_Portal, 1, 1, MC_1_16,
":icons/portal.png",
"Ruined portal",
""
@ -319,15 +321,8 @@ struct StructPos
int cx, cz; // effective center position
};
/* Attempts to construct a list of 48-bit bases that should be further checked.
* Any conditions that would result in a list larger than a buffer size will
* not be preloaded in this way.
*/
void getCandidates(std::vector<int64_t>& list, int mc, const Condition *cond, int ccnt, int64_t bufmax);
int testCond(StructPos *spos, int64_t seed, const Condition *cond, int mc, LayerStack *g, std::atomic_bool *abort);
#endif // SEARCH_H

View File

@ -1,4 +1,8 @@
#include "searchitem.h"
#include "seedtables.h"
#include <QMessageBox>
#include <QStandardPaths>
SearchItem::~SearchItem()
@ -116,10 +120,11 @@ void SearchItem::run()
void SearchItemGenerator::init(
int mc, const Condition *cond, int ccnt,
const std::vector<int64_t>& seedlist,
QObject *mainwin, int mc, const Condition *cond, int ccnt,
Gen48Settings gen48, const std::vector<int64_t>& seedlist,
int itemsize, int searchtype, int64_t sstart)
{
this->mainwin = mainwin;
this->searchtype = searchtype;
this->mc = mc;
this->cond = cond;
@ -127,18 +132,164 @@ void SearchItemGenerator::init(
this->itemid = 0;
this->itemsiz = itemsize;
this->slist = seedlist;
this->gen48 = gen48;
this->idx = 0;
this->scnt = ~(uint64_t)0;
this->seed = sstart;
this->isdone = false;
}
static int check(int64_t s48, void *data)
{
(void) data;
const StructureConfig sconf = {};
return isQuadBaseFeature24(sconf, s48, 7+1, 7+1, 9+1) != 0;
}
static void genQHBases(QObject *qtobj, int qual, int64_t salt, std::vector<int64_t>& list48)
{
const char *lbstr = NULL;
const int64_t *lbset = NULL;
int64_t lbcnt = 0;
QString path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
if (path.isEmpty())
path = "protobases";
switch (qual)
{
case IDEAL_SALTED:
case IDEAL:
lbstr = "ideal";
lbset = low20QuadIdeal;
lbcnt = sizeof(low20QuadIdeal) / sizeof(int64_t);
break;
case CLASSIC:
lbstr = "cassic";
lbset = low20QuadClassic;
lbcnt = sizeof(low20QuadClassic) / sizeof(int64_t);
break;
case NORMAL:
lbstr = "normal";
lbset = low20QuadHutNormal;
lbcnt = sizeof(low20QuadHutNormal) / sizeof(int64_t);
break;
case BARELY:
lbstr = "barely";
lbset = low20QuadHutBarely;
lbcnt = sizeof(low20QuadHutBarely) / sizeof(int64_t);
break;
default:
return;
}
path += QString("/quad_") + lbstr + ".txt";
QByteArray fnam = path.toLatin1();
int64_t *qb = NULL;
int64_t qn = 0;
if ((qb = loadSavedSeeds(fnam.data(), &qn)) == NULL)
{
printf("Writing quad-protobases to: %s\n", fnam.data());
fflush(stdout);
QMetaObject::invokeMethod(qtobj, "openProtobaseMsg", Qt::QueuedConnection, Q_ARG(QString, path));
int threads = QThread::idealThreadCount();
int err = searchAll48(&qb, &qn, fnam.data(), threads, lbset, lbcnt, 20, check, NULL);
if (err)
{
QMetaObject::invokeMethod(
qtobj, "warning", Qt::BlockingQueuedConnection,
Q_ARG(QString, QString("Warning")),
Q_ARG(QString, QString("Failed to generate protobases.")));
return;
}
else
{
QMetaObject::invokeMethod(qtobj, "closeProtobaseMsg", Qt::BlockingQueuedConnection);
}
}
else
{
printf("Loaded quad-protobases from: %s\n", fnam.data());
fflush(stdout);
}
if (qb)
{
// convert protobases to proper bases by subtracting the salt
list48.resize(qn);
for (int64_t i = 0; i < qn; i++)
list48[i] = qb[i] - salt;
free(qb);
}
}
// Produces a list of seed bases from precomputed lists, provided all candidates fit into a buffer.
bool getQuadCandidates(std::vector<int64_t>& list48, QObject *qtobj, Gen48Settings gen48, int mc, int64_t bufmax)
{
std::vector<int64_t> qlist;
list48.clear();
if (gen48.mode == GEN48_QH)
{
int64_t salt = 0;
if (gen48.qual == IDEAL_SALTED)
salt = gen48.salt;
else
salt = (mc <= MC_1_12 ? SWAMP_HUT_CONFIG_112.salt : SWAMP_HUT_CONFIG.salt);
genQHBases(qtobj, gen48.qual, salt, qlist);
}
else if (gen48.mode == GEN48_QM)
{
const int64_t *qb = g_qm_90;
int64_t qn = sizeof(g_qm_90) / sizeof(int64_t);
qlist.reserve(qn);
for (int64_t i = 0; i < qn; i++)
if (qmonumentQual(qb[i]) >= gen48.qmarea)
qlist.push_back(qb[i]);
}
if (qlist.empty())
return false;
int x = gen48.x1;
int z = gen48.z1;
int w = gen48.x2 - x + 1;
int h = gen48.z2 - z + 1;
// does the set of candidates for this condition fit in memory?
if ((int64_t)qlist.size() * (int64_t)sizeof(int64_t) * w*h >= bufmax)
return false;
try {
list48.resize(qlist.size() * w*h);
} catch (...) {
return false;
}
int64_t *p = list48.data();
for (int j = 0; j < h; j++)
for (int i = 0; i < w; i++)
for (int64_t b : qlist)
*p++ = moveStructure(b, x+i, z+j);
std::sort(list48.begin(), list48.end());
auto last = std::unique(list48.begin(), list48.end());
list48.erase(last, list48.end());
return !list48.empty();
}
void SearchItemGenerator::presearch()
{
int64_t sstart = seed;
if (slist.empty() && searchtype != SEARCH_LIST)
getCandidates(slist, mc, cond, ccnt, PRECOMPUTE48_BUFSIZ);
getQuadCandidates(slist, mainwin, gen48, mc, PRECOMPUTE48_BUFSIZ);
if (searchtype == SEARCH_LIST && !slist.empty())
{

View File

@ -8,12 +8,9 @@
#include <QVector>
#include <QElapsedTimer>
#include "settings.h"
#include "search.h"
#define PRECOMPUTE48_BUFSIZ ((int64_t)1 << 30)
// search type options from combobox
enum { SEARCH_INC = 0, SEARCH_BLOCKS = 1, SEARCH_LIST = 2 };
struct SearchItem : public QObject, QRunnable
{
@ -71,24 +68,27 @@ public:
// (or the last entry in the seed list)
};
struct SearchItemGenerator
{
void init(
int mc, const Condition *cond, int ccnt,
const std::vector<int64_t>& slist,
int itemsize, int searchtype, int64_t sstart);
QObject *mainwin, int mc, const Condition *cond, int ccnt,
Gen48Settings gen48, const std::vector<int64_t>& seedlist,
int itemsize, int searchtype, int64_t sstart);
void presearch();
SearchItem *requestItem();
void getProgress(uint64_t *prog, uint64_t *end);
QObject * mainwin;
int searchtype;
int mc;
const Condition * cond;
int ccnt;
uint64_t itemid; // item incrementor
int itemsiz; // number of seeds per search item
Gen48Settings gen48; // 48-bit generator settings
std::vector<int64_t> slist; // candidate list
uint64_t idx; // index within candidate list
uint64_t scnt; // size of search space

View File

@ -1,21 +1,20 @@
#include "searchthread.h"
#include "mainwindow.h"
#include "formsearchcontrol.h"
#include "cutil.h"
#include "mainwindow.h" // TODO: remove
#include <QMessageBox>
#include <QEventLoop>
#include <x86intrin.h>
#define TSC_INTERRUPT_CNT ((uint64_t)1 << 30)
#define ITEM_SIZE 1024
extern MainWindow *gMainWindowInstance;
SearchThread::SearchThread(MainWindow *parent)
SearchThread::SearchThread(FormSearchControl *parent)
: QThread()
, parent(parent)
, condvec()
@ -30,7 +29,8 @@ SearchThread::SearchThread(MainWindow *parent)
itemgen.abort = &abort;
}
bool SearchThread::set(int type, int threads, std::vector<int64_t>& slist64, int64_t sstart, int mc,
bool SearchThread::set(QObject *mainwin, int type, int threads, Gen48Settings gen48,
std::vector<int64_t>& slist, int64_t sstart, int mc,
const QVector<Condition>& cv, int itemsize, int queuesize)
{
char refbuf[100] = {};
@ -95,7 +95,7 @@ bool SearchThread::set(int type, int threads, std::vector<int64_t>& slist64, int
}
condvec = cv;
itemgen.init(mc, condvec.data(), condvec.size(), slist64, itemsize, type, sstart);
itemgen.init(mainwin, mc, condvec.data(), condvec.size(), gen48, slist, itemsize, type, sstart);
pool.setMaxThreadCount(threads);
recieved.resize(queuesize);
lastid = itemgen.itemid;
@ -109,11 +109,18 @@ void SearchThread::run()
{
itemgen.presearch();
pool.waitForDone();
uint64_t prog, end;
itemgen.getProgress(&prog, &end);
emit progress(prog, end, itemgen.seed);
for (int idx = 0; idx < recieved.size(); idx++)
{
recieved[idx].valid = false;
startNextItem();
}
emit searchEnded();
}
@ -126,7 +133,7 @@ SearchItem *SearchThread::startNextItem()
QObject::connect(item, &SearchItem::itemDone, this, &SearchThread::onItemDone, Qt::BlockingQueuedConnection);
QObject::connect(item, &SearchItem::canceled, this, &SearchThread::onItemCanceled, Qt::QueuedConnection);
// redirect results to mainwindow
QObject::connect(item, &SearchItem::results, parent, &MainWindow::searchResultsAdd, Qt::BlockingQueuedConnection);
QObject::connect(item, &SearchItem::results, parent, &FormSearchControl::searchResultsAdd, Qt::BlockingQueuedConnection);
++activecnt;
pool.start(item);
return item;

View File

@ -9,10 +9,8 @@
#include "searchitem.h"
#define PRECOMPUTE48_BUFSIZ ((int64_t)1 << 30)
class MainWindow;
class FormSearchControl;
struct SearchThread : QThread
{
@ -24,9 +22,10 @@ public:
int64_t seed;
};
SearchThread(MainWindow *parent);
SearchThread(FormSearchControl *parent);
bool set(int type, int threads, std::vector<int64_t>& slist64, int64_t sstart, int mc,
bool set(QObject *mainwin, int type, int threads, Gen48Settings gen48,
std::vector<int64_t>& slist, int64_t sstart, int mc,
const QVector<Condition>& cv, int itemsize, int queuesize);
virtual void run() override;
@ -36,14 +35,15 @@ public:
signals:
void progress(uint64_t last, uint64_t end, int64_t seed);
void searchFinish();
void searchEnded(); // search thread is exiting (e.g. abort or done)
void searchFinish(); // search ended and is comlete
public slots:
void onItemDone(uint64_t itemid, int64_t seed, bool isdone);
void onItemCanceled(uint64_t itemid);
public:
MainWindow * parent;
FormSearchControl * parent;
QVector<Condition> condvec;
SearchItemGenerator itemgen;

79
settings.h Normal file
View File

@ -0,0 +1,79 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QThread>
struct Config
{
bool smoothMotion;
bool restoreSession;
int autosaveCycle;
int seedsPerItem;
int queueSize;
int maxMatching;
Config() { reset(); }
void reset()
{
smoothMotion = true;
restoreSession = true;
autosaveCycle = 10;
seedsPerItem = 256;
queueSize = QThread::idealThreadCount();
maxMatching = 65536;
}
};
enum { GEN48_AUTO, GEN48_QH, GEN48_QM, GEN48_LIST, GEN48_NONE };
enum { IDEAL, CLASSIC, NORMAL, BARELY, IDEAL_SALTED };
struct Gen48Settings
{
int mode;
QString slist48path;
int64_t salt;
int qual;
int qmarea;
bool manualarea;
int x1, z1, x2, z2;
Gen48Settings() { reset(); }
void reset()
{
mode = GEN48_AUTO;
slist48path = "";
salt = 0;
qual = IDEAL;
qmarea = 13028;
manualarea = false;
x1 = z1 = x2 = z2 = 0;
}
};
// search type options from combobox
enum { SEARCH_INC = 0, SEARCH_BLOCKS = 1, SEARCH_LIST = 2 };
struct SearchConfig
{
int searchmode;
QString slist64path;
int threads;
int64_t startseed;
bool stoponres;
SearchConfig() { reset(); }
void reset()
{
searchmode = SEARCH_INC;
slist64path = "";
threads = QThread::idealThreadCount();
startseed = 0;
stoponres = true;
}
};
#endif // SETTINGS_H