Added dimensions!

1) updated cubiomes
2) added Nether and End switcher to map viewer
3) added fortress, bastion and end cities and their finders
4) updated analysis function
This commit is contained in:
Cubitect 2021-06-06 17:13:02 +02:00
parent 03ceb1cb4a
commit 10a7fcaea0
25 changed files with 626 additions and 269 deletions

View File

@ -11,6 +11,9 @@ Precompiled binaries can be found for Linux and Windows under [Releases on githu
For the linux build you will probably have to add the executable flags to the binary (github seems to remove them upon upload).
For Arch linux users, the tool may be found in the [AUR](https://aur.archlinux.org/packages/cubiomes-viewer/) thanks to [JakobDev](https://github.com/JakobDev).
## Build from source
Install Qt5 development files

@ -1 +1 @@
Subproject commit 3a6a923553eaf00145b5e162c9e37019e166ad98
Subproject commit a4a422686e5703d4add8d910548e68843ac1cd8a

View File

@ -47,5 +47,17 @@
<file>icons/cancel.png</file>
<file>icons/clear.png</file>
<file>icons/info.png</file>
<file>icons/overworld.png</file>
<file>icons/nether.png</file>
<file>icons/overworld_d.png</file>
<file>icons/the_end_d.png</file>
<file>icons/the_end.png</file>
<file>icons/nether_d.png</file>
<file>icons/fortress_d.png</file>
<file>icons/fortress.png</file>
<file>icons/endcity_d.png</file>
<file>icons/endcity.png</file>
<file>icons/bastion_d.png</file>
<file>icons/bastion.png</file>
</qresource>
</RCC>

BIN
icons/bastion.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
icons/bastion_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
icons/endcity.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
icons/endcity_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
icons/fortress.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
icons/fortress_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
icons/nether.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
icons/nether_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
icons/overworld.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

BIN
icons/overworld_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
icons/the_end.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

BIN
icons/the_end_d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -13,8 +13,8 @@ unsigned char tempsColors[256][3];
int main(int argc, char *argv[])
{
initBiomes();
initBiomeColours(biomeColors);
initBiomeTypeColours(tempsColors);
initBiomeColors(biomeColors);
initBiomeTypeColors(tempsColors);
QApplication a(argc, argv);
MainWindow mw;

View File

@ -71,10 +71,24 @@ MainWindow::MainWindow(QWidget *parent)
//ui->toolBar->setContentsMargins(0, 0, 0, 0);
QAction *toorigin = new QAction(QIcon(":/icons/origin.png"), "Goto origin", this);
toorigin->connect(toorigin, &QAction::triggered, [=](){ this->mapGoto(0,0,16); });
connect(toorigin, &QAction::triggered, [=](){ this->mapGoto(0,0,16); });
ui->toolBar->addAction(toorigin);
ui->toolBar->addSeparator();
dimactions[0] = addMapAction(-1, "overworld", "Overworld");
dimactions[1] = addMapAction(-1, "nether", "Nether");
dimactions[2] = addMapAction(-1, "the_end", "End");
dimgroup = new QActionGroup(this);
for (int i = 0; i < 3; i++)
{
connect(dimactions[i], &QAction::triggered, [=](){ this->updateMapSeed(); });
ui->toolBar->addAction(dimactions[i]);
dimgroup->addAction(dimactions[i]);
}
dimactions[0]->setChecked(true);
ui->toolBar->addSeparator();
saction.resize(STRUCT_NUM);
addMapAction(D_GRID, "grid", "Show grid");
addMapAction(D_SLIME, "slime", "Show slime chunks");
@ -93,6 +107,11 @@ MainWindow::MainWindow(QWidget *parent)
addMapAction(D_PORTAL, "portal", "Show ruined portals");
addMapAction(D_SPAWN, "spawn", "Show world spawn");
addMapAction(D_STRONGHOLD, "stronghold", "Show strongholds");
ui->toolBar->addSeparator();
addMapAction(D_FORTESS, "fortress", "Show nether fortresses");
addMapAction(D_BASTION, "bastion", "Show bastions");
ui->toolBar->addSeparator();
addMapAction(D_ENDCITY, "endcity", "Show end cities");
saction[D_GRID]->setChecked(true);
@ -135,9 +154,12 @@ QAction *MainWindow::addMapAction(int stype, const char *iconpath, const char *t
icon.addPixmap(QPixmap(inam + "_d.png"), QIcon::Normal, QIcon::Off);
QAction *action = new QAction(icon, tip, this);
action->setCheckable(true);
action->connect(action, &QAction::toggled, [=](bool state){ this->onActionMapToggled(stype, state); });
ui->toolBar->addAction(action);
saction[stype] = action;
if (stype >= 0)
{
action->connect(action, &QAction::toggled, [=](bool state){ this->onActionMapToggled(stype, state); });
saction[stype] = action;
}
return action;
}
@ -172,7 +194,7 @@ bool MainWindow::getSeed(int *mc, int64_t *seed, bool applyrand)
return ok;
}
bool MainWindow::setSeed(int mc, int64_t seed)
bool MainWindow::setSeed(int mc, int64_t seed, int dim)
{
const char *mcstr = mc2str(mc);
if (!mcstr)
@ -181,12 +203,25 @@ bool MainWindow::setSeed(int mc, int64_t seed)
return false;
}
if (dim == INT_MAX)
dim = getDim();
ui->comboBoxMC->setCurrentText(mcstr);
ui->seedEdit->setText(QString::asprintf("%" PRId64, seed));
ui->mapView->setSeed(mc, seed);
ui->mapView->setSeed(mc, seed, dim);
return true;
}
int MainWindow::getDim()
{
QAction *active = dimgroup->checkedAction();
if (active == dimactions[1])
return -1; // nether
if (active == dimactions[2])
return +1; // end
return 0;
}
void MainWindow::saveSettings()
{
QSettings settings("cubiomes-viewer", "cubiomes-viewer");
@ -205,6 +240,7 @@ void MainWindow::saveSettings()
getSeed(&mc, &seed, false);
settings.setValue("map/mc", mc);
settings.setValue("map/seed", (qlonglong)seed);
settings.setValue("map/dim", getDim());
settings.setValue("map/x", ui->mapView->getX());
settings.setValue("map/z", ui->mapView->getZ());
settings.setValue("map/scale", ui->mapView->getScale());
@ -235,6 +271,14 @@ void MainWindow::loadSettings()
ui->mapView->setSmoothMotion(config.smoothMotion);
int dim = settings.value("map/dim", getDim()).toInt();
if (dim == -1)
dimactions[1]->setChecked(true);
else if (dim == +1)
dimactions[2]->setChecked(true);
else
dimactions[0]->setChecked(true);
int mc = MC_1_16;
int64_t seed = 0;
getSeed(&mc, &seed, true);
@ -436,7 +480,7 @@ void MainWindow::updateMapSeed()
int mc;
int64_t seed;
if (getSeed(&mc, &seed))
ui->mapView->setSeed(mc, seed);
setSeed(mc, seed);
}
@ -655,30 +699,62 @@ void MainWindow::on_buttonAnalysis_clicked()
warning("Warning", "Invalid area for analysis");
return;
}
if ((int64_t)(x2 - x1) * (int64_t)(z2 - z1) > 100000000LL)
{
QString msg = QString::asprintf(
"Area for analysis is very large (%d, %d).\n"
"The analysis might take a while. Do you want to continue?",
x2-x1+1, z2-z1+1);
int button = QMessageBox::warning(this, "Warning", msg, QMessageBox::Cancel, QMessageBox::Yes);
if (button != QMessageBox::Yes)
return;
}
bool everything = ui->radioEverything->isChecked();
int mc;
int64_t seed;
if (!getSeed(&mc, &seed))
return;
ui->buttonAnalysis->setEnabled(false);
update();
QApplication::processEvents();
const int step = 512;
long idcnt[256] = {0};
int dim = getDim();
LayerStack g;
setupGenerator(&g, mc);
applySeed(&g, seed);
int *ids = allocCache(g.entry_1, step, step);
long idcnt[256] = {0};
for (int x = x1; x <= x2; x += step)
{
for (int z = z1; z <= z2; z += step)
{
int w = x2-x+1 < step ? x2-x+1 : step;
int h = z2-z+1 < step ? z2-z+1 : step;
genArea(g.entry_1, ids, x, z, w, h);
for (int i = 0; i < w*h; i++)
idcnt[ ids[i] & 0xff ]++;
if (everything || dim == 0)
{
genArea(g.entry_1, ids, x, z, w, h);
for (int i = 0; i < w*h; i++)
idcnt[ ids[i] & 0xff ]++;
}
if (everything || dim == -1)
{
genNetherScaled(mc, seed, 1, ids, x, z, w, h, 0, 0);
for (int i = 0; i < w*h; i++)
idcnt[ ids[i] & 0xff ]++;
}
if (everything || dim == +1)
{
genEndScaled(mc, seed, 1, ids, x, z, w, h);
for (int i = 0; i < w*h; i++)
idcnt[ ids[i] & 0xff ]++;
}
}
}
@ -714,13 +790,17 @@ void MainWindow::on_buttonAnalysis_clicked()
tree->insertTopLevelItem(0, item_cat);
std::vector<VarPos> st;
for (int stype = Desert_Pyramid; stype <= Treasure; stype++)
for (int sopt = D_DESERT; sopt < D_SPAWN; sopt++)
{
if (!everything && !getMapView()->getShow(sopt))
continue;
st.clear();
int stype = mapopt2stype(sopt);
StructureConfig sconf;
if (!getConfig(stype, mc, &sconf))
continue;
getStructs(&st, sconf, &g, mc, seed, x1, z1, x2, z2);
getStructs(&st, sconf, mc, seed, x1, z1, x2, z2);
if (st.empty())
continue;
@ -744,41 +824,48 @@ void MainWindow::on_buttonAnalysis_clicked()
tree->insertTopLevelItem(stype, item_cat);
}
Pos pos = getSpawn(mc, &g, NULL, seed);
if (pos.x >= x1 && pos.x <= x2 && pos.z >= z1 && pos.z <= z2)
if (everything || getMapView()->getShow(D_SPAWN))
{
item_cat = new QTreeWidgetItem(tree);
item_cat->setText(0, "Spawn");
item_cat->setData(1, Qt::DisplayRole, QVariant::fromValue(1));
QTreeWidgetItem* item = new QTreeWidgetItem(item_cat);
item->setData(0, Qt::UserRole, QVariant::fromValue(pos));
item->setText(0, QString::asprintf("%d,\t%d", pos.x, pos.z));
}
StrongholdIter sh;
initFirstStronghold(&sh, mc, seed);
std::vector<Pos> shp;
while (nextStronghold(&sh, &g, NULL) > 0)
{
pos = sh.pos;
Pos pos = getSpawn(mc, &g, NULL, seed);
if (pos.x >= x1 && pos.x <= x2 && pos.z >= z1 && pos.z <= z2)
shp.push_back(pos);
}
if (!shp.empty())
{
item_cat = new QTreeWidgetItem(tree);
item_cat->setText(0, "Stronghold");
item_cat->setData(1, Qt::DisplayRole, QVariant::fromValue(shp.size()));
for (Pos pos : shp)
{
item_cat = new QTreeWidgetItem(tree);
item_cat->setText(0, "Spawn");
item_cat->setData(1, Qt::DisplayRole, QVariant::fromValue(1));
QTreeWidgetItem* item = new QTreeWidgetItem(item_cat);
item->setData(0, Qt::UserRole, QVariant::fromValue(pos));
item->setText(0, QString::asprintf("%d,\t%d", pos.x, pos.z));
}
}
if (everything || getMapView()->getShow(D_STRONGHOLD))
{
StrongholdIter sh;
initFirstStronghold(&sh, mc, seed);
std::vector<Pos> shp;
while (nextStronghold(&sh, &g, NULL) > 0)
{
Pos pos = sh.pos;
if (pos.x >= x1 && pos.x <= x2 && pos.z >= z1 && pos.z <= z2)
shp.push_back(pos);
}
if (!shp.empty())
{
item_cat = new QTreeWidgetItem(tree);
item_cat->setText(0, "Stronghold");
item_cat->setData(1, Qt::DisplayRole, QVariant::fromValue(shp.size()));
for (Pos pos : shp)
{
QTreeWidgetItem* item = new QTreeWidgetItem(item_cat);
item->setData(0, Qt::UserRole, QVariant::fromValue(pos));
item->setText(0, QString::asprintf("%d,\t%d", pos.x, pos.z));
}
}
}
ui->buttonExport->setEnabled(true);
ui->buttonAnalysis->setEnabled(true);
}
void MainWindow::on_buttonExport_clicked()

View File

@ -6,6 +6,8 @@
#include <QTableWidgetItem>
#include <QTreeWidgetItem>
#include <QWidget>
#include <QAction>
#include <QActionGroup>
#include <QTimer>
#include <QThreadPool>
@ -44,7 +46,8 @@ public:
QAction *addMapAction(int stype, const char *iconpath, const char *tip);
bool getSeed(int *mc, int64_t *seed, bool applyrand = true);
bool setSeed(int mc, int64_t seed);
bool setSeed(int mc, int64_t seed, int dim = INT_MAX);
int getDim();
MapView *getMapView();
protected:
@ -110,6 +113,9 @@ public:
QTimer autosaveTimer;
QVector<QAction*> saction;
QAction *dimactions[3];
QActionGroup *dimgroup;
ProtoBaseDialog *protodialog;
};

View File

@ -62,6 +62,16 @@ QSplitter::handle:vertical {
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="labelSeed">
<property name="toolTip">
<string>Seed can be an integer or text. Leave empty for a random seed</string>
</property>
<property name="text">
<string>seed:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labeMC">
<property name="toolTip">
@ -88,16 +98,6 @@ QSplitter::handle:vertical {
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="labelSeed">
<property name="toolTip">
<string>Seed can be an integer or text. Leave empty for a random seed</string>
</property>
<property name="text">
<string>seed:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxMC">
<property name="toolTip">
@ -283,7 +283,67 @@ QSplitter::handle:vertical {
<string>Analysis</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_7">
<item row="1" column="0" colspan="2">
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="lineRadius">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QPushButton" name="buttonExport">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Export</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="5">
<widget class="QTreeWidget" name="treeAnalysis">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::NoDragDrop</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerDefaultSectionSize">
<number>280</number>
</attribute>
<column>
<property name="text">
<string>object</string>
</property>
</column>
<column>
<property name="text">
<string>count</string>
</property>
</column>
</widget>
</item>
<item row="1" column="0" colspan="3">
<layout class="QHBoxLayout" name="layoutArea">
<item>
<widget class="QLabel" name="labelX1">
@ -380,6 +440,13 @@ QSplitter::handle:vertical {
</item>
</layout>
</item>
<item row="1" column="3" colspan="2">
<widget class="QPushButton" name="buttonFromVisible">
<property name="text">
<string>From visible</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelSquareArea">
<property name="text">
@ -387,31 +454,7 @@ QSplitter::handle:vertical {
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="buttonExport">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Export</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QPushButton" name="buttonAnalysis">
<property name="text">
<string>Analyze</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineRadius">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<item row="0" column="3" colspan="2">
<widget class="QCheckBox" name="cboxArea">
<property name="toolTip">
<string>Specify manual rectangle rather than square</string>
@ -424,55 +467,33 @@ QSplitter::handle:vertical {
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<widget class="QTreeWidget" name="treeAnalysis">
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
<item row="4" column="0" colspan="5">
<widget class="QPushButton" name="buttonAnalysis">
<property name="text">
<string>Analyze</string>
</property>
<property name="font">
<font>
<family>Monospace</family>
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::NoDragDrop</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerDefaultSectionSize">
<number>280</number>
</attribute>
<column>
<property name="text">
<string>object</string>
</property>
</column>
<column>
<property name="text">
<string>count</string>
</property>
</column>
</widget>
</item>
<item row="1" column="2" colspan="2">
<widget class="QPushButton" name="buttonFromVisible">
<property name="text">
<string>From visible</string>
</property>
</widget>
<item row="2" column="0" colspan="5">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QRadioButton" name="radioStructs">
<property name="text">
<string>Selected structures</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioEverything">
<property name="text">
<string>Everything</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -72,7 +72,7 @@ MapView::~MapView()
delete overlay;
}
void MapView::setSeed(int mc, int64_t s)
void MapView::setSeed(int mc, int64_t s, int dim)
{
prevx = focusx = getX();
prevz = focusz = getZ();
@ -80,7 +80,11 @@ void MapView::setSeed(int mc, int64_t s)
if (world == NULL || world->mc != mc || world->seed != s)
{
delete world;
world = new QWorld(mc, s);
world = new QWorld(mc, s, dim);
}
else if (world->dim != dim)
{
world->setDim(dim);
}
settingsToWorld();
update(2);
@ -185,7 +189,7 @@ void MapView::paintEvent(QPaintEvent *)
qreal bz = (cur.y() - height()/2) / blocks2pix + fz;
Pos p = {(int)bx, (int)bz};
overlay->pos = p;
overlay->id = getBiomeAtPos(&world->g, p);
overlay->id = world->getBiome(p);
if (QThreadPool::globalInstance()->activeThreadCount() > 0 || velx || velz)
updatecounter = 2;

View File

@ -36,7 +36,7 @@ public:
qreal getZ();
qreal getScale() const { return 1.0 / blocks2pix; }
void setSeed(int mc, int64_t s);
void setSeed(int mc, int64_t s, int dim);
void setView(qreal x, qreal z, qreal scale = 0);
bool getShow(int stype) { return stype >= 0 && stype < STRUCT_NUM ? sshow[stype] : false; }

View File

@ -9,8 +9,8 @@
Quad::Quad(const Level* l, int i, int j)
: mc(l->mc),entry(l->entry),seed(l->seed)
, ti(i),tj(j),blocks(l->blocks),pixs(l->pixs),stype(l->stype)
: mc(l->mc),seed(l->seed),dim(l->dim),entry(l->entry)
, ti(i),tj(j),blocks(l->blocks),pixs(l->pixs),sopt(l->sopt)
, rgb(),img(),spos()
, done()
, prio(),stopped()
@ -26,8 +26,25 @@ Quad::~Quad()
}
void getStructs(std::vector<VarPos> *out, const StructureConfig sconf,
LayerStack *g, int mc, int64_t seed, int x0, int z0, int x1, int z1)
int mc, int64_t seed, int x0, int z0, int x1, int z1)
{
union {
LayerStack g;
NetherNoise nn;
EndNoise en;
} u;
int dim;
if (sconf.structType == Fortress || sconf.structType == Bastion)
dim = -1;
else if (sconf.structType == End_City)
dim = +1;
else
{
dim = 0;
setupGenerator(&u.g, mc);
}
int si0 = (int)floor(x0 / (qreal)(sconf.regionSize * 16));
int sj0 = (int)floor(z0 / (qreal)(sconf.regionSize * 16));
int si1 = (int)floor((x1-1) / (qreal)(sconf.regionSize * 16));
@ -43,7 +60,26 @@ void getStructs(std::vector<VarPos> *out, const StructureConfig sconf,
if (p.x >= x0 && p.x < x1 && p.z >= z0 && p.z < z1)
{
int id = isViableStructurePos(sconf.structType, mc, g, seed, p.x, p.z);
int id = 0;
if (dim == 0)
{
id = isViableStructurePos(sconf.structType, mc, &u.g, seed, p.x, p.z);
}
else if (dim == -1)
{
id = isViableNetherStructurePos(sconf.structType, mc, &u.nn, seed, p.x, p.z);
}
else if (dim == +1)
{
id = isViableEndStructurePos(sconf.structType, mc, &u.en, seed, p.x, p.z);
if (id)
{
SurfaceNoise sn;
initSurfaceNoiseEnd(&sn, seed);
id = isViableEndCityTerrain(&u.en, &sn, p.x, p.z);
}
}
if (id)
{
VarPos vp = { p, 0 };
@ -60,6 +96,7 @@ void getStructs(std::vector<VarPos> *out, const StructureConfig sconf,
}
void Quad::run()
{
if (done)
@ -67,9 +104,23 @@ void Quad::run()
if (pixs > 0)
{
int *b = allocCache(entry, pixs, pixs);
genArea(entry, b, ti*pixs, tj*pixs, pixs, pixs);
int x = ti*pixs, z = tj*pixs, w = pixs, h = pixs;
int *b = NULL;
if (dim == -1)
{
b = (int*) malloc((pixs+7) * (pixs+7) * sizeof(int));
genNetherScaled(mc, seed, blocks / pixs, b, x, z, w, h, 0, 0);
}
else if (dim == +1) // end
{
b = (int*) malloc((pixs+7) * (pixs+7) * sizeof(int));
genEndScaled(mc, seed, blocks / pixs, b, x, z, w, h);
}
else
{
b = allocCache(entry, pixs, pixs);
genArea(entry, b, x, z, w, h);
}
rgb = new uchar[pixs*pixs * 3];
biomesToImage(rgb, biomeColors, b, pixs, pixs, 1, 1);
@ -78,34 +129,15 @@ void Quad::run()
}
else
{
int structureType = -1;
switch (stype)
{
case D_DESERT: structureType = Desert_Pyramid; break;
case D_JUNGLE: structureType = Jungle_Pyramid; break;
case D_IGLOO: structureType = Igloo; break;
case D_HUT: structureType = Swamp_Hut; break;
case D_VILLAGE: structureType = Village; break;
case D_MANSION: structureType = Mansion; break;
case D_MONUMENT: structureType = Monument; break;
case D_RUINS: structureType = Ocean_Ruin; break;
case D_SHIPWRECK: structureType = Shipwreck; break;
case D_TREASURE: structureType = Treasure; break;
case D_OUTPOST: structureType = Outpost; break;
case D_PORTAL: structureType = Ruined_Portal; break;
}
int structureType = mapopt2stype(sopt);
if (structureType >= 0)
{
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);
getStructs(st, sconf, mc, seed, x0, z0, x1, z1);
spos = st;
}
}
@ -114,10 +146,10 @@ void Quad::run()
Level::Level()
: cells(),g(),entry(),seed(),mc()
: cells(),g(),entry(),seed(),mc(),dim()
, tx(),tz(),tw(),th()
, scale(),blocks(),pixs()
, stype()
, sopt()
{
}
@ -181,64 +213,70 @@ int mapOceanMixMod(const Layer * l, int * out, int x, int z, int w, int h)
return 0;
}
void Level::init4map(int mcversion, int64_t ws, int pix, int layerscale)
void Level::init4map(int mcversion, int64_t ws, int dim, int pix, int layerscale)
{
mc = mcversion;
seed = ws;
setupGenerator(&g, mc);
this->mc = mcversion;
this->seed = ws;
this->dim = dim;
tx = tz = tw = th = 0;
scale = layerscale;
pixs = pix;
blocks = pix * layerscale;
stype = D_NONE;
sopt = D_NONE;
switch (scale)
if (dim == 0) // overworld
{
case 1:
entry = g.entry_1;
break;
case 4:
entry = g.entry_4;
break;
case 16:
if (mc >= MC_1_13) {
entry = setupLayer(&g, L_VORONOI_1, &mapOceanMixMod, mc, 1, 0, 0, &g.layers[L_SHORE_16], &g.layers[L_ZOOM_16_OCEAN]);
} else {
entry = g.entry_16;
}
break;
case 64:
if (mc >= MC_1_13) {
entry = setupLayer(&g, L_VORONOI_1, &mapOceanMixMod, mc, 1, 0, 0, &g.layers[L_SUNFLOWER_64], &g.layers[L_ZOOM_64_OCEAN]);
} else {
entry = g.entry_64;
}
break;
case 256:
if (mc >= MC_1_13) {
int layerid = mc >= MC_1_14 ? L_BAMBOO_256 : L_BIOME_256;
entry = setupLayer(&g, L_VORONOI_1, &mapOceanMixMod, mc, 1, 0, 0, &g.layers[layerid], &g.layers[L_OCEAN_TEMP_256]);
} else {
entry = g.entry_256;
}
break;
default:
printf("Bad scale (%d) for level\n", scale);
exit(1);
}
setupGenerator(&g, mc);
setLayerSeed(entry, seed);
switch (scale)
{
case 1:
entry = g.entry_1;
break;
case 4:
entry = g.entry_4;
break;
case 16:
if (mc >= MC_1_13) {
entry = setupLayer(&g, L_VORONOI_1, &mapOceanMixMod, mc, 1, 0, 0, &g.layers[L_SHORE_16], &g.layers[L_ZOOM_16_OCEAN]);
} else {
entry = g.entry_16;
}
break;
case 64:
if (mc >= MC_1_13) {
entry = setupLayer(&g, L_VORONOI_1, &mapOceanMixMod, mc, 1, 0, 0, &g.layers[L_SUNFLOWER_64], &g.layers[L_ZOOM_64_OCEAN]);
} else {
entry = g.entry_64;
}
break;
case 256:
if (mc >= MC_1_13) {
int layerid = mc >= MC_1_14 ? L_BAMBOO_256 : L_BIOME_256;
entry = setupLayer(&g, L_VORONOI_1, &mapOceanMixMod, mc, 1, 0, 0, &g.layers[layerid], &g.layers[L_OCEAN_TEMP_256]);
} else {
entry = g.entry_256;
}
break;
default:
printf("Bad scale (%d) for level\n", scale);
exit(1);
}
setLayerSeed(entry, seed);
}
}
void Level::init4struct(int mcversion, int64_t ws, int b, int structtype, int lv)
{
mc = mcversion;
dim = 0;
seed = ws;
blocks = b;
pixs = -1;
scale = -1;
stype = structtype;
sopt = structtype;
viewlv = lv;
}
@ -268,7 +306,7 @@ void Level::resizeLevel(std::vector<Quad*>& cache, int x, int z, int w, int h)
int gx = c->ti - x;
int gz = c->tj - z;
if (c->blocks == blocks && c->stype == stype)
if (c->blocks == blocks && c->sopt == sopt && c->dim == dim)
{
// remove outside quads from schedule
if (QThreadPool::globalInstance()->tryTake(c))
@ -308,6 +346,8 @@ void Level::resizeLevel(std::vector<Quad*>& cache, int x, int z, int w, int h)
{
g->stopped = false;
g->prio = sqdist(i-w/2, j-h/2);
if (g->dim != dim)
g->prio += 1000000;
togen.push_back(g);
}
}
@ -348,13 +388,15 @@ void Level::update(std::vector<Quad*>& cache, qreal bx0, qreal bz0, qreal bx1, q
}
QWorld::QWorld(int mc, int64_t seed)
QWorld::QWorld(int mc, int64_t seed, int dim)
: mc(mc)
, seed(seed)
, lv()
, dim(dim)
, sha()
, lvb()
, lvs()
, activelv()
, cached()
, cachedbiomes()
, cachedstruct()
, cachesize()
, spawn()
@ -373,6 +415,7 @@ QWorld::QWorld(int mc, int64_t seed)
{
setupGenerator(&g, mc);
applySeed(&g, seed);
sha = getVoronoiSHA(seed);
activelv = 0;
@ -390,12 +433,27 @@ QWorld::QWorld(int mc, int64_t seed)
lvs[D_TREASURE].init4struct(mc, seed, 2048, D_TREASURE, 1);
lvs[D_OUTPOST].init4struct(mc, seed, 2048, D_OUTPOST, 2);
lvs[D_PORTAL].init4struct(mc, seed, 2048, D_PORTAL, 1);
lv.resize(5);
lv[0].init4map(mc, seed, pixs, 1);
lv[1].init4map(mc, seed, pixs, 4);
lv[2].init4map(mc, seed, pixs, 16);
lv[3].init4map(mc, seed, pixs, 64);
lv[4].init4map(mc, seed, pixs, 256);
lvs[D_FORTESS].init4struct(mc, seed, 2048, D_FORTESS, 1);
lvs[D_BASTION].init4struct(mc, seed, 2048, D_BASTION, 1);
lvs[D_ENDCITY].init4struct(mc, seed, 2048, D_ENDCITY, 1);
if (dim == 0)
{
lvb.resize(5);
lvb[0].init4map(mc, seed, dim, pixs, 1);
lvb[1].init4map(mc, seed, dim, pixs, 4);
lvb[2].init4map(mc, seed, dim, pixs, 16);
lvb[3].init4map(mc, seed, dim, pixs, 64);
lvb[4].init4map(mc, seed, dim, pixs, 256);
}
else
{
lvb.resize(4);
lvb[0].init4map(mc, seed, dim, pixs, 1);
lvb[1].init4map(mc, seed, dim, pixs, 4);
lvb[2].init4map(mc, seed, dim, pixs, 16);
lvb[3].init4map(mc, seed, dim, pixs, 64);
}
cachesize = 100;
qual = 1.0;
@ -415,6 +473,9 @@ QWorld::QWorld(int mc, int64_t seed)
icons[D_PORTAL] = QPixmap(":/icons/portal.png");
icons[D_SPAWN] = QPixmap(":/icons/spawn.png");
icons[D_STRONGHOLD] = QPixmap(":/icons/stronghold.png");
icons[D_FORTESS] = QPixmap(":/icons/fortress.png");
icons[D_BASTION] = QPixmap(":/icons/bastion.png");
icons[D_ENDCITY] = QPixmap(":/icons/endcity.png");
iconzvil = QPixmap(":/icons/zombie.png");
}
@ -424,7 +485,7 @@ QWorld::~QWorld()
isdel = true;
QThreadPool::globalInstance()->clear();
QThreadPool::globalInstance()->waitForDone();
for (Quad *q : cached)
for (Quad *q : cachedbiomes)
delete q;
for (Quad *q : cachedstruct)
delete q;
@ -435,6 +496,71 @@ QWorld::~QWorld()
}
}
void QWorld::setDim(int dim)
{
QThreadPool::globalInstance()->clear();
QThreadPool::globalInstance()->waitForDone();
this->dim = dim;
// cache existing quads
for (Level& l : lvb)
{
std::vector<Quad*> todel;
for (Quad *q : l.cells)
{
if (q->done)
cachedbiomes.push_back(q);
else
todel.push_back(q);
}
l.cells.swap(todel);
}
cleancache(cachedbiomes, (int)(cachesize));
lvb.clear();
int pixs = 512;
if (dim == 0)
{
lvb.resize(5);
lvb[0].init4map(mc, seed, dim, pixs, 1);
lvb[1].init4map(mc, seed, dim, pixs, 4);
lvb[2].init4map(mc, seed, dim, pixs, 16);
lvb[3].init4map(mc, seed, dim, pixs, 64);
lvb[4].init4map(mc, seed, dim, pixs, 256);
}
else
{
lvb.resize(4);
lvb[0].init4map(mc, seed, dim, pixs, 1);
lvb[1].init4map(mc, seed, dim, pixs, 4);
lvb[2].init4map(mc, seed, dim, pixs, 16);
lvb[3].init4map(mc, seed, dim, pixs, 64);
}
}
int QWorld::getBiome(Pos p)
{
if (dim == -1)
{
if (mc < MC_1_16)
return nether_wastes;
NetherNoise nn;
setNetherSeed(&nn, seed);
voronoiAccess3D(sha, p.x, 0, p.z, &p.x, 0, &p.z);
return getNetherBiome(&nn, p.x, 0, p.z, NULL);
}
else if (dim == 1)
{
if (mc < MC_1_9)
return the_end;
int buf[49];
genEndScaled(mc, seed, 1, buf, p.x, p.z, 1, 1);
return buf[0];
}
return getBiomeAtPos(&g, p);
}
void QWorld::cleancache(std::vector<Quad*>& cache, unsigned int maxsize)
{
// try to delete the oldest entries in the cache
@ -515,18 +641,18 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
qreal bx1 = focusx + uiw/2;
qreal bz1 = focusz + uih/2;
if (blocks2pix >= qual) activelv = -1;
else if (blocks2pix >= qual/4) activelv = 0;
else if (blocks2pix >= qual/16) activelv = 1;
else if (blocks2pix >= qual/64) activelv = 2;
if (blocks2pix >= qual) activelv = -1;
else if (blocks2pix >= qual/4) activelv = 0;
else if (blocks2pix >= qual/16) activelv = 1;
else if (blocks2pix >= qual/64) activelv = 2;
else if (blocks2pix >= qual/256) activelv = 3;
else activelv = lv.size()-1;
else activelv = lvb.size()-1;
for (int li = activelv+1; li >= activelv; --li)
{
if (li < 0 || li >= (int)lv.size())
if (li < 0 || li >= (int)lvb.size())
continue;
Level& l = lv[li];
Level& l = lvb[li];
for (Quad *q : l.cells)
{
if (!q->img)
@ -598,10 +724,10 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
}
for (int stype = D_DESERT; stype < D_SPAWN; stype++)
for (int sopt = D_DESERT; sopt < D_SPAWN; sopt++)
{
Level& l = lvs[stype];
if (!sshow[stype] || activelv > l.viewlv)
Level& l = lvs[sopt];
if (!sshow[sopt] || activelv > l.viewlv)
continue;
std::vector<QPainter::PixmapFragment> frags;
@ -615,12 +741,13 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
{
qreal x = vw/2 + (vp.p.x - focusx) * blocks2pix;
qreal y = vh/2 + (vp.p.z - focusz) * blocks2pix;
if (x < 0 || x >= vw || y < 0 || y >= vh)
continue;
QPointF d = QPointF(x, y);
QRectF r = icons[stype].rect();
if (stype == D_VILLAGE)
QRectF r = icons[sopt].rect();
if (sopt == D_VILLAGE)
{
if (vp.variant) {
painter.drawPixmap(x-r.width()/2, y-r.height()/2, iconzvil);
@ -638,7 +765,7 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
r.moveCenter(d);
if (r.contains(selx, selz))
{
seltype = stype;
seltype = sopt;
selpos = vp.p;
selvar = vp.variant;
}
@ -646,7 +773,7 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
}
}
painter.drawPixmapFragments(frags.data(), frags.size(), icons[stype]);
painter.drawPixmapFragments(frags.data(), frags.size(), icons[sopt]);
}
Pos* sp = spawn; // atomic fetch
@ -698,17 +825,18 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
painter.drawPixmapFragments(frags.data(), frags.size(), icons[D_STRONGHOLD]);
}
for (int li = lv.size()-1; li >= 0; --li)
for (int li = lvb.size()-1; li >= 0; --li)
{
Level& l = lvb[li];
if (li == activelv || li == activelv+1)
lv[li].update(cached, bx0, bz0, bx1, bz1);
l.update(cachedbiomes, bx0, bz0, bx1, bz1);
else
lv[li].update(cached, 0, 0, 0, 0);
l.update(cachedbiomes, 0, 0, 0, 0);
}
for (int stype = D_DESERT; stype < D_SPAWN; stype++)
for (int sopt = D_DESERT; sopt < D_SPAWN; sopt++)
{
Level& l = lvs[stype];
if (activelv <= l.viewlv && sshow[stype])
Level& l = lvs[sopt];
if (activelv <= l.viewlv && sshow[sopt])
l.update(cachedstruct, bx0, bz0, bx1, bz1);
else if (activelv > l.viewlv+1)
l.update(cachedstruct, 0, 0, 0, 0);
@ -764,7 +892,7 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz,
painter.drawPixmap(iconrec.translated(pad,pad), *icon);
}
cleancache(cached, cachesize);
cleancache(cachedbiomes, cachesize);
cleancache(cachedstruct, cachesize);
}

View File

@ -10,8 +10,10 @@
enum {
D_NONE = -1,
// generics
D_GRID,
D_SLIME,
// structures
D_DESERT,
D_JUNGLE,
D_IGLOO,
@ -24,6 +26,10 @@ enum {
D_TREASURE,
D_OUTPOST,
D_PORTAL,
D_FORTESS,
D_BASTION,
D_ENDCITY,
// non-recurring structures
D_SPAWN,
D_STRONGHOLD,
STRUCT_NUM
@ -49,6 +55,9 @@ inline const char *mapopt2str(int opt)
case D_PORTAL: return "portal";
case D_SPAWN: return "spawn";
case D_STRONGHOLD: return "stronghold";
case D_FORTESS: return "fortress";
case D_BASTION: return "bastion";
case D_ENDCITY: return "endcity";
default: return "";
}
}
@ -71,9 +80,36 @@ inline int str2mapopt(const char *s)
if (!strcmp(s, "portal")) return D_PORTAL;
if (!strcmp(s, "spawn")) return D_SPAWN;
if (!strcmp(s, "stronghold")) return D_STRONGHOLD;
if (!strcmp(s, "fortress")) return D_FORTESS;
if (!strcmp(s, "bastion")) return D_BASTION;
if (!strcmp(s, "endcity")) return D_ENDCITY;
return D_NONE;
}
inline int mapopt2stype(int opt)
{
switch (opt)
{
case D_DESERT: return Desert_Pyramid;
case D_JUNGLE: return Jungle_Pyramid;
case D_IGLOO: return Igloo;
case D_HUT: return Swamp_Hut;
case D_VILLAGE: return Village;
case D_MANSION: return Mansion;
case D_MONUMENT: return Monument;
case D_RUINS: return Ocean_Ruin;
case D_SHIPWRECK: return Shipwreck;
case D_TREASURE: return Treasure;
case D_OUTPOST: return Outpost;
case D_PORTAL: return Ruined_Portal;
case D_FORTESS: return Fortress;
case D_BASTION: return Bastion;
case D_ENDCITY: return End_City;
default:
return -1;
}
}
struct Level;
struct VarPos
@ -83,7 +119,7 @@ struct VarPos
};
void getStructs(std::vector<VarPos> *out, const StructureConfig sconf,
LayerStack *g, int mc, int64_t seed, int x0, int z0, int x1, int z1);
int mc, int64_t seed, int x0, int z0, int x1, int z1);
class Quad : public QRunnable
{
@ -94,12 +130,13 @@ public:
void run();
int mc;
const Layer *entry;
int64_t seed;
int dim;
const Layer *entry;
int ti, tj;
int blocks;
int pixs;
int stype;
int sopt;
uchar *rgb;
@ -121,8 +158,8 @@ struct Level
Level();
~Level();
void init4map(int mc, int64_t ws, int pix, int layerscale);
void init4struct(int mc, int64_t ws, int blocks, int stype, int viewlv);
void init4map(int mc, int64_t ws, int dim, int pix, int layerscale);
void init4struct(int mc, int64_t ws, int blocks, int sopt, int viewlv);
void resizeLevel(std::vector<Quad*>& cache, int x, int z, int w, int h);
void update(std::vector<Quad*>& cache, qreal bx0, qreal bz0, qreal bx1, qreal bz1);
@ -132,37 +169,43 @@ struct Level
Layer *entry;
int64_t seed;
int mc;
int dim;
int tx, tz, tw, th;
int scale;
int blocks;
int pixs;
int stype;
int sopt;
int viewlv;
};
struct QWorld
{
QWorld(int mc, int64_t seed);
QWorld(int mc, int64_t seed, int dim = 0);
~QWorld();
void setDim(int dim);
void cleancache(std::vector<Quad*>& cache, unsigned int maxsize);
void draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz, qreal blocks2pix);
int getBiome(Pos p);
int mc;
int64_t seed;
int dim;
LayerStack g;
int64_t sha;
// the visible area is managed in Quads of different scales (for biomes and structures),
// which are managed in rectangular sections as levels
std::vector<Level> lv; // levels for biomes
std::vector<Level> lvb; // levels for biomes
std::vector<Level> lvs; // levels for structures
int activelv; // currently visible level
// processed Quads are cached until they are too far out of view
std::vector<Quad*> cached;
std::vector<Quad*> cachedbiomes;
std::vector<Quad*> cachedstruct;
unsigned int cachesize;

View File

@ -182,6 +182,11 @@ L_qm_any:
case F_TREASURE:
case F_PORTAL:
case F_FORTRESS:
case F_BASTION:
case F_ENDCITY:
x1 = cond->x1;
z1 = cond->z1;
x2 = cond->x2;
@ -232,8 +237,30 @@ L_qm_any:
continue;
if (pc.x >= x1 && pc.x <= x2 && pc.z >= z1 && pc.z <= z2)
{
if (g && !isViableStructurePos(sconf.structType, mc, g, seed, pc.x, pc.z))
continue;
if (g)
{
if (finfo.dim == 0 && !isViableStructurePos(sconf.structType, mc, g, seed, pc.x, pc.z))
continue;
if (finfo.dim == -1)
{
NetherNoise nn;
if (!isViableNetherStructurePos(sconf.structType, mc, &nn, seed, pc.x, pc.z))
continue;
}
if (finfo.dim == +1)
{
EndNoise en;
if (!isViableEndStructurePos(sconf.structType, mc, &en, seed, pc.x, pc.z))
continue;
if (sconf.structType == End_City)
{
SurfaceNoise sn; // TODO: store for reuse?
initSurfaceNoiseEnd(&sn, seed);
if (!isViableEndCityTerrain(&en, &sn, pc.x, pc.z))
continue;
}
}
}
xt += pc.x;
zt += pc.z;
@ -250,6 +277,7 @@ L_qm_any:
}
return 0;
case F_SPAWN:
// TODO: warn if spawn is used for relative positioning
sout->cx = 0;

View File

@ -24,6 +24,7 @@ struct FilterInfo
int step; // coordinate multiplier
int count; //
int mcmin; // minimum version
int dim; // dimension
const char *icon;
const char *name;
const char *desription;
@ -60,6 +61,9 @@ enum
F_RUINS,
F_SHIPWRECK,
F_PORTAL,
F_FORTRESS,
F_BASTION,
F_ENDCITY,
FILTER_MAX,
};
@ -71,14 +75,14 @@ static const struct FilterList
FilterList() : list{}
{
list[F_SELECT] = FilterInfo{
CAT_NONE, 0, 0, 0, 0, 0, 0, MC_1_0,
CAT_NONE, 0, 0, 0, 0, 0, 0, MC_1_0, 0,
NULL,
"",
""
};
list[F_QH_IDEAL] = FilterInfo{
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4, 0,
":icons/quad.png",
"Quad-hut (ideal)",
"The lower 48-bits provide potential for four swamp huts in "
@ -86,7 +90,7 @@ static const struct FilterList
};
list[F_QH_CLASSIC] = FilterInfo{
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4, 0,
":icons/quad.png",
"Quad-hut (classic)",
"The lower 48-bits provide potential for four swamp huts in "
@ -96,7 +100,7 @@ static const struct FilterList
};
list[F_QH_NORMAL] = FilterInfo{
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4, 0,
":icons/quad.png",
"Quad-hut (normal)",
"The lower 48-bits provide potential for four swamp huts in "
@ -106,7 +110,7 @@ static const struct FilterList
};
list[F_QH_BARELY] = FilterInfo{
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4,
CAT_48, 1, 1, 0, Swamp_Hut, 512, 0, MC_1_4, 0,
":icons/quad.png",
"Quad-hut (barely)",
"The lower 48-bits provide potential for four swamp huts in "
@ -115,7 +119,7 @@ static const struct FilterList
};
list[F_QM_95] = FilterInfo{
CAT_48, 1, 1, 0, Monument, 512, 0, MC_1_8,
CAT_48, 1, 1, 0, Monument, 512, 0, MC_1_8, 0,
":icons/quad.png",
"Quad-ocean-monument (>95%)",
"The lower 48-bits provide potential for 95% of the area of "
@ -124,7 +128,7 @@ static const struct FilterList
};
list[F_QM_90] = FilterInfo{
CAT_48, 1, 1, 0, Monument, 512, 0, MC_1_8,
CAT_48, 1, 1, 0, Monument, 512, 0, MC_1_8, 0,
":icons/quad.png",
"Quad-ocean-monument (>90%)",
"The lower 48-bits provide potential for 90% of the area of "
@ -133,7 +137,7 @@ static const struct FilterList
};
list[F_BIOME] = FilterInfo{
CAT_FULL, 1, 1, L_VORONOI_1, 0, 1, 0, MC_1_0,
CAT_FULL, 1, 1, L_VORONOI_1, 0, 1, 0, MC_1_0, 0,
":icons/map.png",
"Biome filter 1:1",
"Only seeds with the included (+) biomes in the specified area and "
@ -141,7 +145,7 @@ static const struct FilterList
};
list[F_BIOME_4_RIVER] = FilterInfo{
CAT_FULL, 1, 1, L_RIVER_MIX_4, 0, 4, 0, MC_1_0,
CAT_FULL, 1, 1, L_RIVER_MIX_4, 0, 4, 0, MC_1_0, 0,
":icons/map.png",
"Biome filter 1:4 RIVER",
"Only seeds with the included (+) biomes in the specified area and "
@ -150,7 +154,7 @@ static const struct FilterList
};
list[F_BIOME_16_SHORE] = FilterInfo{
CAT_FULL, 1, 1, L_SHORE_16, 0, 16, 0, MC_1_0,
CAT_FULL, 1, 1, L_SHORE_16, 0, 16, 0, MC_1_0, 0,
":icons/map.png",
"Biome filter 1:16 SHORE",
"Only seeds with the included (+) biomes in the specified area and "
@ -159,7 +163,7 @@ static const struct FilterList
};
list[F_BIOME_64_RARE] = FilterInfo{
CAT_FULL, 1, 1, L_SUNFLOWER_64, 0, 64, 0, MC_1_7,
CAT_FULL, 1, 1, L_SUNFLOWER_64, 0, 64, 0, MC_1_7, 0,
":icons/map.png",
"Biome filter 1:64 RARE",
"Only seeds with the included (+) biomes in the specified area and "
@ -168,7 +172,7 @@ static const struct FilterList
};
list[F_BIOME_256_BIOME] = FilterInfo{
CAT_FULL, 1, 1, L_BIOME_256, 0, 256, 0, MC_1_0,
CAT_FULL, 1, 1, L_BIOME_256, 0, 256, 0, MC_1_0, 0,
":icons/map.png",
"Biome filter 1:256 BIOME",
"Only seeds with the included (+) biomes in the specified area and "
@ -177,7 +181,7 @@ static const struct FilterList
};
list[F_BIOME_256_OTEMP] = FilterInfo{
CAT_48, 1, 1, L_OCEAN_TEMP_256, 0, 256, 0, MC_1_13,
CAT_48, 1, 1, L_OCEAN_TEMP_256, 0, 256, 0, MC_1_13, 0,
":icons/map.png",
"Biome filter 1:256 O.TEMP",
"Only seeds with the included (+) biomes in the specified area and "
@ -187,116 +191,137 @@ static const struct FilterList
};
list[F_TEMPS] = FilterInfo{
CAT_FULL, 1, 1, 0, 0, 1024, 0, MC_1_7,
CAT_FULL, 1, 1, 0, 0, 1024, 0, MC_1_7, 0,
":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, 0, 16, 1, MC_1_0,
CAT_FULL, 1, 1, 0, 0, 16, 1, MC_1_0, 0,
":icons/slime.png",
"Slime chunk",
""
};
list[F_SPAWN] = FilterInfo{
CAT_FULL, 1, 1, 0, 0, 1, 0, MC_1_0,
CAT_FULL, 1, 1, 0, 0, 1, 0, MC_1_0, 0,
":icons/spawn.png",
"Spawn",
""
};
list[F_STRONGHOLD] = FilterInfo{
CAT_FULL, 1, 1, 0, 0, 1, 1, MC_1_0,
CAT_FULL, 1, 1, 0, 0, 1, 1, MC_1_0, 0,
":icons/stronghold.png",
"Stronghold",
""
};
list[F_DESERT] = FilterInfo{
CAT_FULL, 1, 1, 0, Desert_Pyramid, 1, 1, MC_1_3,
CAT_FULL, 1, 1, 0, Desert_Pyramid, 1, 1, MC_1_3, 0,
":icons/desert.png",
"Desert pyramid",
""
};
list[F_JUNGLE] = FilterInfo{
CAT_FULL, 1, 1, 0, Jungle_Pyramid, 1, 1, MC_1_3,
CAT_FULL, 1, 1, 0, Jungle_Pyramid, 1, 1, MC_1_3, 0,
":icons/jungle.png",
"Jungle temple",
""
};
list[F_HUT] = FilterInfo{
CAT_FULL, 1, 1, 0, Swamp_Hut, 1, 1, MC_1_4,
CAT_FULL, 1, 1, 0, Swamp_Hut, 1, 1, MC_1_4, 0,
":icons/hut.png",
"Swamp hut",
""
};
list[F_IGLOO] = FilterInfo{
CAT_FULL, 1, 1, 0, Igloo, 1, 1, MC_1_9,
CAT_FULL, 1, 1, 0, Igloo, 1, 1, MC_1_9, 0,
":icons/igloo.png",
"Igloo",
""
};
list[F_MONUMENT] = FilterInfo{
CAT_FULL, 1, 1, 0, Monument, 1, 1, MC_1_8,
CAT_FULL, 1, 1, 0, Monument, 1, 1, MC_1_8, 0,
":icons/monument.png",
"Ocean monument",
""
};
list[F_VILLAGE] = FilterInfo{
CAT_FULL, 1, 1, 0, Village, 1, 1, MC_1_0,
CAT_FULL, 1, 1, 0, Village, 1, 1, MC_1_0, 0,
":icons/village.png",
"Village",
""
};
list[F_OUTPOST] = FilterInfo{
CAT_FULL, 1, 1, 0, Outpost, 1, 1, MC_1_14,
CAT_FULL, 1, 1, 0, Outpost, 1, 1, MC_1_14, 0,
":icons/outpost.png",
"Pillager outpost",
""
};
list[F_MANSION] = FilterInfo{
CAT_FULL, 1, 1, 0, Mansion, 1, 1, MC_1_11,
CAT_FULL, 1, 1, 0, Mansion, 1, 1, MC_1_11, 0,
":icons/mansion.png",
"Woodland mansion",
""
};
list[F_TREASURE] = FilterInfo{
CAT_FULL, 1, 1, 0, Treasure, 1, 1, MC_1_13,
CAT_FULL, 1, 1, 0, Treasure, 1, 1, MC_1_13, 0,
":icons/treasure.png",
"Buried treasure",
""
};
list[F_RUINS] = FilterInfo{
CAT_FULL, 1, 1, 0, Ocean_Ruin, 1, 1, MC_1_13,
CAT_FULL, 1, 1, 0, Ocean_Ruin, 1, 1, MC_1_13, 0,
":icons/ruins.png",
"Ocean ruins",
""
};
list[F_SHIPWRECK] = FilterInfo{
CAT_FULL, 1, 1, 0, Shipwreck, 1, 1, MC_1_13,
CAT_FULL, 1, 1, 0, Shipwreck, 1, 1, MC_1_13, 0,
":icons/shipwreck.png",
"Shipwreck",
""
};
list[F_PORTAL] = FilterInfo{
CAT_FULL, 1, 1, 0, Ruined_Portal, 1, 1, MC_1_16,
CAT_FULL, 1, 1, 0, Ruined_Portal, 1, 1, MC_1_16, 0,
":icons/portal.png",
"Ruined portal",
""
};
list[F_FORTRESS] = FilterInfo{
CAT_FULL, 1, 1, 0, Fortress, 1, 1, MC_1_0, -1,
":icons/fortress.png",
"Nether fortress",
""
};
list[F_BASTION] = FilterInfo{
CAT_FULL, 1, 1, 0, Bastion, 1, 1, MC_1_16, -1,
":icons/bastion.png",
"Bastion remnant",
""
};
list[F_ENDCITY] = FilterInfo{
CAT_FULL, 1, 1, 0, End_City, 1, 1, MC_1_9, +1,
":icons/endcity.png",
"End city",
""
};
}
}
g_filterinfo;