From 0b03caccc421bbb50bb78905ce9e78ac8a41e66e Mon Sep 17 00:00:00 2001 From: Cubitect Date: Sun, 28 Jan 2024 19:59:45 +0100 Subject: [PATCH] Feature changes 4.0.0 * added inverted range check for climate extremes * added option to redistribure condtion IDs * updated german translations * updated metadata * moved scaling of Biome filters to a filter option * moved Nether and End biome filters to the Biome category * enabled Voronoi biome filters (use only when neccessary) * removed Triggers tab, since the Locations tab includes its functionality --- .github/workflows/windows-release.yaml | 15 +- cubiomes | 2 +- ...om.github.cubitect.cubiomes-viewer.desktop | 0 ...thub.cubitect.cubiomes-viewer.metainfo.xml | 10 +- etc/icon.svg | 355 +--- rc/examples.qrc | 1 - rc/examples/quadhut_stronghold_mushroom.txt | 11 +- rc/icons/logo.png | Bin 5602 -> 8843 bytes rc/lang/de_DE.qm | Bin 86091 -> 90159 bytes rc/lang/de_DE.ts | 1611 +++++++++-------- src/conditiondialog.cpp | 290 +-- src/conditiondialog.h | 6 +- src/conditiondialog.ui | 302 +-- src/formconditions.cpp | 3 +- src/formsearchcontrol.cpp | 56 +- src/headless.cpp | 6 +- src/headless.h | 2 + src/layerdialog.cpp | 8 +- src/main.cpp | 3 +- src/mainwindow.cpp | 28 +- src/mainwindow.h | 1 + src/mainwindow.ui | 7 + src/mapview.cpp | 6 +- src/presetdialog.cpp | 21 +- src/search.cpp | 138 +- src/search.h | 232 +-- src/searchthread.cpp | 29 +- src/tabbiomes.cpp | 12 +- src/tablocations.cpp | 16 +- src/tablocations.ui | 2 +- src/tabstructures.cpp | 26 +- src/tabtriggers.cpp | 8 +- src/util.cpp | 13 + src/util.h | 6 + src/world.cpp | 12 +- 35 files changed, 1625 insertions(+), 1613 deletions(-) mode change 100755 => 100644 etc/com.github.cubitect.cubiomes-viewer.desktop diff --git a/.github/workflows/windows-release.yaml b/.github/workflows/windows-release.yaml index 76ee237..0329e9f 100644 --- a/.github/workflows/windows-release.yaml +++ b/.github/workflows/windows-release.yaml @@ -3,18 +3,19 @@ name: Windows Release on: push: branches: - - 'main' + - 'trunk' tags: - 'v*' -defaults: - run: - shell: cmd - env: PROG: cubiomes-viewer SOURCE_DIR: ${{github.workspace}} +defaults: + run: + shell: cmd + working-directory: ${{env.SOURCE_DIR}} + jobs: build: runs-on: windows-2019 @@ -26,7 +27,6 @@ jobs: submodules: recursive - name: (2) Get all tags for correct version determination - working-directory: ${{env.SOURCE_DIR}} run: | git fetch --all --tags -f @@ -43,13 +43,11 @@ jobs: setup-python: false - name: (4) Build - working-directory: ${{env.SOURCE_DIR}} run: | qmake CONFIG+=release ${{env.SOURCE_DIR}} mingw32-make - name: (5) Deploy - working-directory: ${{env.SOURCE_DIR}} run: | mkdir ${{env.PROG}} copy ${{env.SOURCE_DIR}}\release\${{env.PROG}}.exe ${{env.PROG}} @@ -61,3 +59,4 @@ jobs: name: ${{env.PROG}}-${{github.ref_name}}-win path: ${{env.SOURCE_DIR}}\${{env.PROG}} + diff --git a/cubiomes b/cubiomes index c3ff21a..1163e4e 160000 --- a/cubiomes +++ b/cubiomes @@ -1 +1 @@ -Subproject commit c3ff21a1a8b6bf362221db3f4dee71a0dc7dba9b +Subproject commit 1163e4ec21ba142c393802c9667a3c5addeef807 diff --git a/etc/com.github.cubitect.cubiomes-viewer.desktop b/etc/com.github.cubitect.cubiomes-viewer.desktop old mode 100755 new mode 100644 diff --git a/etc/com.github.cubitect.cubiomes-viewer.metainfo.xml b/etc/com.github.cubitect.cubiomes-viewer.metainfo.xml index 810f332..a35eb99 100644 --- a/etc/com.github.cubitect.cubiomes-viewer.metainfo.xml +++ b/etc/com.github.cubitect.cubiomes-viewer.metainfo.xml @@ -16,15 +16,19 @@

This release adds a way to find locations in a given seed, as well as a biome sample filter that can check biome proportions.

-

All scaled coordinates have been changed to use block coordinates instead. Scaled iterators now have scaling option.

+

All scaled coordinates have been changed to use block coordinates instead. Scaled biome filters and iterators now have a scaling option.

Changes:

  • Added Locations tab to look for position in the current seed
  • -
  • Added biome samples filter to check biome proportions
  • +
  • Added filter for Biome Samples to check biome proportions
  • Added outline display for the area of selected conditions
  • Added "from-visible" to conditions editor
  • Added headless mode to search seeds without a GUI using --nogui
  • -
  • Removed Triggers tab, since the Locations tab replaces the functionality
  • +
  • Moved scaling of Biome filters to a filter option
  • +
  • Moved step size of Iterators to a filter option
  • +
  • Moved Nether and End biome filters to the Biome category
  • +
  • Enabled Voronoi biome filters (use only when neccessary)
  • +
  • Removed Triggers tab, since the Locations tab includes its functionality
diff --git a/etc/icon.svg b/etc/icon.svg index 41e9c4e..388d8a7 100644 --- a/etc/icon.svg +++ b/etc/icon.svg @@ -8,8 +8,11 @@ version="1.1" id="svg5" xml:space="preserve" - sodipodi:docname="logo.svg" - inkscape:version="1.2.1 (ef4d3fba62, 2022-07-19, custom)" + sodipodi:docname="icon.svg" + inkscape:version="1.3.2 (091e20e, 2023-11-25)" + inkscape:export-filename="../rc/icons/logo.png" + inkscape:export-xdpi="48" + inkscape:export-ydpi="48" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -26,12 +29,12 @@ inkscape:document-units="px" showgrid="true" inkscape:zoom="3.0217733" - inkscape:cx="110.20019" - inkscape:cy="123.10652" + inkscape:cx="197.40065" + inkscape:cy="115.82603" inkscape:window-width="1920" - inkscape:window-height="1051" + inkscape:window-height="983" inkscape:window-x="0" - inkscape:window-y="29" + inkscape:window-y="27" inkscape:window-maximized="1" inkscape:current-layer="layer1"> diff --git a/rc/examples.qrc b/rc/examples.qrc index a375cd0..0342058 100644 --- a/rc/examples.qrc +++ b/rc/examples.qrc @@ -5,7 +5,6 @@ examples/mushroom_icespike.txt examples/biome_diversity_1_18.txt examples/old_growth_taiga_somewhere.txt - examples/large_birch_forest_1_18.txt examples/huge_jungle_1_18.txt examples/portal_village_or_treasure.txt examples/two_zombie_villages.txt diff --git a/rc/examples/quadhut_stronghold_mushroom.txt b/rc/examples/quadhut_stronghold_mushroom.txt index ddaf253..a65d728 100644 --- a/rc/examples/quadhut_stronghold_mushroom.txt +++ b/rc/examples/quadhut_stronghold_mushroom.txt @@ -1,7 +1,6 @@ -#Version: 2.0.0 +#Version: 4.0.0 #Mode48: 0 -#HutQual: 0 -#Cond: 01000000fdfffffffdffffff020000000200000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -#Cond: 1300000000ffffff00ffffff000100000001000002000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -#Cond: 370000000000000000000000000000000000000003000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000003f0000000000000091010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -#Cond: 0b000000fdfffffffdffffff020000000200000004000000010000000000000001000000000000000000000000000000004000000000000000000000000000000040000000000000000000000000000000400000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +#Cond: 0100000000faffff00faffffff050000ff050000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000010000200000000000000000000000000000000000000000000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000000000000000000000000000000 +#Cond: 1300000000000000000000000000000000000000020000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +#Cond: 370000000000000000000000000000000000000003000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000003f000000000000009101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +#Cond: 0700000000fdffff00fdffffff020000ff02000004000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000001040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000003f000000000000000000000000000000000000000000000000000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000080ffffff7f00000000000000000000000000000000 diff --git a/rc/icons/logo.png b/rc/icons/logo.png index 72d306ab1bb8185a9c6c113559f3c1b6e39dfe41..dfa7c81d85cd1d17b1c6e6a4aedfc2501350fafd 100644 GIT binary patch delta 8825 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 literal 5602 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 CF~gt$ delta 9878 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 XEj?Shz+jqtHtWl(6iI(zuH63sidMrp diff --git a/rc/lang/de_DE.ts b/rc/lang/de_DE.ts index 414751b..3bb7e5f 100644 --- a/rc/lang/de_DE.ts +++ b/rc/lang/de_DE.ts @@ -14,6 +14,14 @@ + + AnalysisLocations + + + at + bei + + AnalysisTriggers @@ -677,740 +685,821 @@ ConditionDialog - + Condition Editor Editieren der Suchbedingung - + MC: 1.X - + Select category Kategorie auswählen - + Algorithm helpers Algorithmenhelfer - + Quad-structure Quad-Struktur - + Structures Strukturen - - + + Biomes Biome - - Nether biomes - Biome-Nether - - - - End biomes - Biome-Ende - - - - + + Select type Typ auswählen - + Condition type: Bedingungstyp: - + General Generelles - + Condition enabled Bedingung aktiv - + Label: Beschreibung: - - + + Location Ort - - - - - + + + + + Lower bound (inclusive) Untere Grenze (einschließlich) - + X<sub>1</sub>: - - - - - - - - - + + + + + + + + + 0 - + Z<sub>1</sub>: - - - - - + + + + + Upper bound (inclusive) Obere Grenze (einschließlich) - + X<sub>2</sub>: - + Z<sub>2</sub>: - + Within centred square of side: Quadrat mit Seitenlänge: - + Custom: Benutzerdefiniert: - + Location is relative to: Position ist relativ zu: - + World origin Ursprung (0,0) - + Instances within area: Instanzen im Bereich: - + 0 (exclude) 0 (Exkludieren) - + Skip instances at exactly the relative reference location Instanzen an der Referenzposition ignorieren - + Within radial distance: Innerhalb radialer Distanz: - + Ignore reference Referenz ignorieren - + Details Details - + None Keine - + Enables optimizations that trade some accuracy for speed Erlaube austausch von Genauigkeit für Geschwindingkeit - + Approximate Approximieren - + <html><head/><body><p style="white-space:pre">Satisfied if <span style=" font-weight:600;">any</span> of the checked biomes are present</p></body></html> <html><head/><body><p style="white-space:pre">Erfüllt wenn <span style=" font-weight:600;">beliebige</span> der gewählten Biome vorhanden sind</p></body></html> - + Match any Beliebige - - + Sample at height (Y): Evaluierungshöhe (Y): - - + + 256 (Surface) 256 (Oberfläche) - - + + From visible + Sichtbarer Bereich + + + + Y: + Y: + + + + + Proportion of the area that has to be of the included biomes + Mindestanteil der Fläche mit den inkludierten Biomen + + + + + Statistical confidence that the coverage has been reached + Statistische sicherheit, dass die Abdeckung erreicht ist + + + + 128 (Nether Roof) 128 (Nether Decke) - - + + 62 (Sea Level) 62 (Meeresspiegel) - - + + 48 - - + + 32 - - + + 16 - - + + -16 - - + + -32 - - + + -48 - - + + -64 (Bedrock) - + uncheck all Alle abwählen - + include all Alle Inkludieren - + exclude all Alle Exkludieren - + + Biome scale: + Biommaßstab: + + + + Required coverage (%): + Erforderte Abdeckung (%): + + + + Confidence (%): + Statistische Sicherheit (%): + + + + Instead of estimating the center of the allowed biome area, +yield each sampled position individually + Anstelle das Zentrum der erlaubten Biome zu ermitteln +werden die Stichprobenpunkte einzeln weitergegeben + + + + Yield individual samples + Einzelne Orte auflösen + + + Locate biome center Biom lokalisieren - + Border tolerance: Toleranz für den Biomrand: - + Biome: Biom: - + 1 - + Minimum area: Minimale Fläche: - + (? sq. chunks) - + Temperature categories Temeraturkategorieen - + Select how many entries of each temperature category are required. Auswahl der Anzahl von Einträgen von jeder Teperaturkategorie erforderlich sind. - + Climate parameters Klimaparameter - + Select the minimum required and maximum allowed climate parameters: Auswahl der minimal erforderten und maximal erlaubten Klimaparameter: - + <html><head/><body><p>The climate has to enter the required range</p><p>With the <span style=" font-style:italic;">complete</span> modifier, the entire range must be covered</p></body></html> <html><head/><body><p>Das Klima muss in die Grenzen eintreten</p><p>Mit der <span style=" font-style:italic;">vollständig</span> Option muss der ganze Werteberich innerhalb der Grenzen liegen</p></body></html> - + Required: Erforderlich: - + Climate Klima - + <html><head/><body><p>The climate must remain inside the confinement range</p></body></html> <html><head/><body><p>Das Klima muss innerhalb der Grenzen bleiben</p></body></html> - + Confined: Begrenzung: - + <html><head/><body><p>Resulting biomes (<span style=" font-weight:600;">at least one</span> with <img src=":/icons/check_include.png"/>, <span style=" font-weight:600;">any</span> with <img src=":/icons/check_unchecked.png"/>, <span style=" font-weight:600;">none</span> with <img src=":/icons/check_exclude.png"/>):</p></body></html> <html><head/><body><p>Resultat (<span style=" font-weight:600;">Mindestens eins</span> mit <img src=":/icons/check_include.png"/>, <span style=" font-weight:600;">beliebige</span> mit <img src=":/icons/check_unchecked.png"/>, <span style=" font-weight:600;">keine</span> mit <img src=":/icons/check_exclude.png"/>):</p></body></html> - + Locate climate minimum/maximum Klima Minima/Maxima lokalizieren - + + Only match if value is outside the given range + Wert muss außerhalb des Wertebereichs liegen + + + If value is in range: Wenn der Wert im Bereich liegt: - + Climate parameter: Klimaparameter: - + - - + <html><head/><body><p>Lower bound (inclusive)</p></body></html> <html><head/><body><p>Untere Grenze (abgeschlossen)</p></body></html> - + -Infinity -Unendlich - + <html><head/><body><p>Upper bound (inclusive)</p></body></html> <html><head/><body><p>Untere Grenze (abgeschlossen)</p></body></html> - + +Infinity +Unendlich - + Generate up to octave: Bis zur Oktave: - + Minimum Minimum - + Maximum Maximum - + Yield position of: Koordinaten zurückgeben vom: - + + Invert range + Grenzen invertieren + + + Approximate surface height Approxmierte Oberfächenhohe - + Height (Y-level) Höhe (Y-Level) - + Inside range: Innerhalb der Grenzen: - + Outside range: Außerhalb der Grenzen: - + Edit Bearbeiten - + Save as... Speichern als... - + Examples... Example... - + Save Speichern - + Errors Fehler - + Lua script: Lua Skript: - + Open directory... Ordner öffnen... - + + Spiral iterator + Spiral Iterator + + + + Step size: + Schrittgröße: + + + + 512 + + + + Village variants Dorfvarianten - - - + + + Allow only structures that start with one of the selected pieces Nur Strukturen welche mit einer der gewählten Konstruktionen beginnt - - - + + + Filter starting piece Konstuktionsstart - + Abandoned Verlassen - + Bastion variants Bastionvarianten - + Fortress pieces Festungsvarianten - + <html><head/><body><p>Maximum continuous square bounding box</p></body></html> <html><head/><body><p>Maximale quadratische Bounding Box</p></body></html> - + With 2x2 arrangement of bridge crossings or start piece Mit 2x2 Anordung von Start- oder Brückenkreuzungskonstruktion - + Ruined portal variants Portalruinenvaianten - + End city variants Endsiedlungsvarianten - + End ship Schiff - + Igloo variants Igluvarianten - + Basement Keller - - + + Generates any of: Generiert beliebige von: - + Description/Notes Beschreibung/Notizen - + MC %1 Minecraft version - + Other Andere - + Oceanic Ozean - + Warm Warm - + Lush Üppig - + Cold Kalt - + Freezing Frost - + Special Warm Ungewöhlich warm - + Special Lush Ungewöhlich üppig - + Special Cold Ungewohnlich kalt - + Temperature Temperatur - + Humidity Feuchtigkeit - + Continentalness Kontinentalheit - + Erosion Erosion - + Depth Tiefe - + Weirdness Verrücktheit - - + + -Inf - - + + +Inf - + Require full range instead of intersection Erfordert vollen Grenzbereich anstelle einer Überschneidung - + -Inf - + +Inf - + [script not found] [Skript nicht gefunden] + + + The biome locator checks for %n instance(s), each of size %1, which cannot be satisfied by an area of size +%2%3%4 = %5 < %6 @ scale 1:%7. + + + + + - - Location (coordinates are multiplied by %1) - Ort (Koordinaten werden mit %1 multipliziert) + + No Allowed Biomes + Keine Erlaubten Biome - - From floor(-x/2)%1 to floor(x/2)%1 on both axes (inclusive) - Von floor(-x/2)%1 bis floor(x/2)%1 auf beiden Axen (einschließlich) + + The set of allowed biomes is empty, which can never be satisfied. Please include some biomes for the required proportion. + Die Menge von erlaubten Biomen ist leer. Bitte mindestens ein Biom für die erforderte Abdeckung inkludieren. - - Lower bound %1 (inclusive) - Untere Grenze %1 (einschießlich) + + Bad Area for Quad-Structure + Schlechte Flächendefinition für Quad-Strukturen - - Upper bound %1 (inclusive) - Obere Grenze %1 (einschießlich) + + The selected area does not contain a range where a quad-structure can generate. + +Continue anyway? + Die ausgewählte Fläche enthält kein Intervall in der Quad-Strukturen vorkommen. + +Trozdem fortfahren? - + From floor(-x/2) to floor(x/2) on both axes (inclusive) Von floor(-x/2) bis floor(x/2) auf beiden Axen (einschließlich) - + + Sampling scale: + Biommaßstab: + + + + Generation layer: + Generator Lage: + + + No allowed start pieces specified. Condition can never be true. Kein erlaubter Konstruktionsstart angegeben. Bedingung ist nie wahr. - + Missing Start Piece Kein Konstruktionsstart - + The condition contains a climate range which is unbounded with the full range required, which can never be satisfied. Die Bedingung erwartet unbeschränkte Klimagrenzen as gefordert, was nie zutreffen kann. - + Bad Climate Range Schlechte Klimagrenzen - - The biome locator checks for %1 instances of size %2 each, which cannot be satisfied by an area of size %3%4%5 = %6. - Die Biomlakalizierung prüft %1 Instanzen mit jeweils Größe %2, was nicht von einem Bereich %3%4%5 = %6 erfüllt werden kann. - - - + Area Insufficient Bereich ist zu klein - + Bad Surface Height Schlechte Oberflächenhöhe - + Cave biomes do not generate above Y = 246. You should consider lowering the sampling height. Continue anyway? @@ -1419,72 +1508,72 @@ Continue anyway? Trozdem fortfahren? - + Help: area entry Hilfe: Bereichseingabe - - <html><head/><body><p>The area can be entered via <b>custom</b> rectangle, that is defined by its two opposing corners, relative to a center point. These bounds are inclusive.</p><p>Alternatively, the area can be defined as a <b>centered square</b> with a certain side length. In this case the area has the bounds: [-X/2, -X/2] on both axes, rounding down and bounds included. For example a centered square with side 3 will go from -2 to 1 for both the X and Z axes.</p><p>Important to note is that some filters have a scaling associated with them. This means that the area is not defined in blocks, but on a grid with the given spacing (such as chunks instead of blocks). A scaling of 1:16, for example, means that the aforementioned centered square of side 3 will range from -32 to 31 in block coordinates. (Chunk 1 has blocks 16 to 31.)</p></body></html> + + <html><head/><body><p>The area can be entered via <b>custom</b> rectangle, that is defined by its two opposing corners, relative to a center point. These bounds are inclusive.</p><p>Alternatively, the area can be defined as a <b>centered square</b> with a certain side length. In this case the area has the bounds: [-X/2, +X/2] on both axes, rounding down and bounds included. For example a centered square with side 3 will go from -2 to 1 for both the X and Z axes.</p><p>Some filters have a scaling associated with them. This means the condition only checks on a grid with that spacing. An area with a range from -21 to 21 at scale 1:16 may effectively be expanded to -32 to 31, and get sampled at -32, -16, 0 and 16.</p></body></html> - + (~%1 sq. chunks) (~%1 Chunks) - + (%1 sq. chunks) (%1 Chunks) - + Unsaved changes Ungespeicherte Änderungen - + Discard unsaved changes? Ungespeicherte Änderungen verwerfen? - + Save lua script Lua Skript speichern - + Lua script (*.lua) Lua Skript (*.lua) - + Empty check functions Leere check Funktion - + Village along the way from A to B - + Lua examples Lua Beispiele - + Replace editor content with example: Den Editorinhalt mit Beispiel ersetzen: - + Help: Lua script Hilfe: Lua Skript - + <html><head/><body><p>Lua scripts allow the user to write custom filters. A valid Lua filtering script has to define a</p><p><b>check(seed, at, deps)</b></p><p>function, that evaluates when a seed satisfies the condition. It should return a <b>x, z</b> value pair that is the block position for other conditions to reference as the relative location. If the condition fails, the function can return <b>nil</b> instead.</p><p>The arguments of <b>check()</b> are in order:</p><p><dl><dt><b>seed</b><dd>the current world seed<dt><b>at</b> = {x, z}<dd>the relative location of the parent condition<dt><b>deps</b> = [..]{x, z, id, parent}<dd>a list of tables with information on the dependent conditions (i.e. those later in the conditions list)</dl></p><p>Optionally, the script can also define a <b>check48()</b> function, with a similar prototype, that tests whether a given 48-bit seed base is worth investigating further.</p><p>A few global symbols are predefined. These include the biome ID and structure type enums from cubiomes, which means they can be referred to by their names (such as <b>flower_forest</b> or <b>Village</b>). Furthermore, the following functions are available:</p><p><dl><dt><b>getBiomeAt(x, z)</b><dt><b>getBiomeAt(x, y, z)</b><dd>returns the overworld biome at the given block coordinates</p><p><dt><b>getStructures(type, x1, z1, x2, z2)</b><dd>returns a list of <b>{x, z}</b> structure positions for the specified structure <b>type</b> within the area spanning the block positions <b>x1, z1</b> to <b>x2, z2</b>, or <b>nil</b> upon failure</p></body></html> @@ -1504,15 +1593,15 @@ Trozdem fortfahren? Restore previous session at launch - Vorherige Sitzung beim Start widerherstellen + Vorherige Sitzung beim Start wiederherstellen - + Autosave every: Autosave jede: - + min @@ -1537,12 +1626,12 @@ Trozdem fortfahren? Wenn notwendig - + Map View Karte - + Icon scale: Symbolskalierung: @@ -1567,12 +1656,12 @@ Trozdem fortfahren? Maximale Anzahl von Ergebnis Seeds: - + Miscellaneous Anderes - + Check GitHub for updates at startup Prüfe GitHub beim Start nach Updates @@ -1587,24 +1676,24 @@ Trozdem fortfahren? Monospacefont: - + Outline known bounding boxes Bekannte Bounding Boxes zeichnen - + Custom grid multiplier: Raster Skalierungsfaktor: - + MB - + <html><head/><body><p>Simulate inertia for the map view</p></body></html> - + <html><head/><body><p>Massenträgkeit der Karte simulieren</p></body></html> @@ -1612,38 +1701,43 @@ Trozdem fortfahren? Anwendungsfont: - + + Restore window position + Fensterposition wiederherstellen + + + Smooth map motion Gleichmäßige Kartenbewegung - - + + None Keine - + 2 - + 4 - + 5 - + 10 - + Threads for map: Threads für die Karte: @@ -1658,19 +1752,19 @@ Trozdem fortfahren? Dunkel - + Use a fixed grid in blocks instead of outlining the generated map tiles Leave blank for the default behaviour Manueller Rasterabstand, ansonsten wird ein Umriss um jedes Kartensegment gezeichnet leer lassen für das Standardverhalten - + Custom grid spacing: Rasterabstand: - + Map cache size: Cache für Karte: @@ -2075,523 +2169,409 @@ Fortfahren und Überschreiben? [Kein Skript] - + missing script for condition %1 Fehlender Skript für Bedingung %1 - + Condition %1: Bedingung %1: - + OR logic gate OR Logik - + Evaluates as true when any of the conditions that reference it (by relative location) are met. When no referencing conditions are defined, it defaults to true. - + NOT logic gate NOT Logik - + Evaluates as true when none of the conditions that reference it (by relative location) are met. When no referencing conditions are defined, it defaults to true. - + Lua Lua - + Define custom conditions using Lua scripts. - + Coordinate factor x/8 Koordinaten x/8 - + Divides relative location by 8, from Overworld to Nether. - + Coordinate factor x*8 Koordinaten x*8 - + Multiplies relative location by 8, from Nether to Overworld. - - <html><head/><body>Spiral iterator conditions can be used to move a testing position across a given area using a certain step size. Other conditions that refer to it as a relative location will be checked at each step. The iteration is performed in a spiral, so positions closer to the center get priority.</body></html> - - - - - Spiral iterator 1:1 - Spiral Iterator 1:1 - - - - Spiral iterator 1:4 - Spiral Iterator 1:4 - - - - Spiral iterator 1:16 - Spiral Iterator 1:16 - - - - Spiral iterator 1:64 - Spiral Iterator 1:64 - - - - Spiral iterator 1:256 - Spiral Iterator 1:256 + + Spiral iterator + Spiral Iterator - - Spiral iterator 1:512 - Spiral Iterator 1:512 - - - - Spiral iterator 1:1024 - Spiral Iterator 1:1024 + + <html><head/><body>Spiral iterator conditions can be used to move a testing position across a given area using a certain step size. Other conditions that refer to it as a relative location will be checked at each step. The iteration is performed in a spiral, so positions closer to the center get priority.</body></html> + - + Quad-hut (ideal) Quad-Hut (Ideal) - + The lower 48-bits provide potential for four swamp huts in spawning range, in one of the best configurations that exist. - + Quad-hut (classic) Quad-Hut (Klassisch) - + The lower 48-bits provide potential for four swamp huts in spawning range, in one of the "classic" configurations. (Checks for huts in the nearest 2x2 chunk corners of each region.) - + Quad-hut (normal) Quad-Hut (Normal) - + The lower 48-bits provide potential for four swamp huts in spawning range, such that all of them are within 128 blocks of a single AFK location, including a vertical tolerance for a fall damage chute. - + Quad-hut (barely) Quad-Hut (Dürftig) - + The lower 48-bits provide potential for four swamp huts in spawning range, in any configuration, such that the bounding boxes are within 128 blocks of a single AFK location. - + Quad-ocean-monument (>95%) Quad-Monument (>95%) - + The lower 48-bits provide potential for 95% of the area of four ocean monuments to be within 128 blocks of an AFK location. - + Quad-ocean-monument (>90%) Quad-Monument (>90%) - + The lower 48-bits provide potential for 90% of the area of four ocean monuments to be within 128 blocks of an AFK location. - - Biomes 1:1 - Biome 1:1 - - - - - - - + Allows only seeds with the included (+) biomes in the specified area and discard those that have biomes that are explicitly excluded (-). - - Biomes 1:4 - Biome 1:4 - - - - Biomes 1:16 - Biome 1:16 - - - - Biomes 1:64 - Biome 1:64 - - - - Biomes 1:256 - Biome 1:256 - - - - Biomes 1:4 RIVER - Biome 1:4 RIVER - - - + Allows only seeds with the included (+) biomes in the specified area and discard those that have biomes that are explicitly excluded (-) at layer RIVER with scale 1:4. This layer does not generate ocean variants. - - Biomes 1:256 O.TEMP - Biome 1:256 O.TEMP - - - + Allows only seeds with the included (+) biomes in the specified area and discard those that have biomes that are explicitly excluded (-) at layer OCEAN TEMPERATURE with scale 1:256. This generation layer depends only on the lower 48-bits of the seed. - - Climate parameters 1:4 - Klimaparameter 1:4 - - - + Custom limits for the required and allowed climate noise parameters that the specified area should cover. - - Locate climate extreme 1:4 - Klimaextrem Lokalisieren 1:4 - - - + Finds the location where a climate parameter reaches its minimum or maximum. - - Locate biome center 1:4 - Biomzentrum Lokalisieren 1:4 - - - + Finds the center position of a given biome. - + Locate biome center 1:256 Biomzentrum Lokalisieren 1:256 - + Finds the center position of a given biome. Based on the 1:256 biome layer. - + Temperature categories Temeraturkategorieen - + Checks that the area has a minimum of all the required temperature categories. - - Nether biomes 1:1 (disabled) - Netherbiome 1:1 (inaktiv) - - - - Nether biomes after voronoi scaling to 1:1. - - - - - Nether biomes 1:4 - Netherbiome 1:4 - - - - Nether biomes with normal noise sampling at scale 1:4. - - - - - Nether biomes 1:16 - Netherbiome 1:16 + + Biome samples + Biom Stichproben - - Nether biomes, but only sampled at scale 1:16. + + Samples biomes in a given area to find if a proportion of the biomes match a set of allowed biomes. - - Nether biomes 1:64 - Netherbiome 1:64 - - - - Nether biomes, but only sampled at scale 1:64. - + + Overworld at scale + Oberwelt bei Maßstab - - Nether biomes 1:256 - Netherbiome 1:256 + + Nether at scale + Nether bei Maßstab - - Nether biomes, but only sampled at scale 1:256. + + Nether biomes sampled on a scaled grid. - - End biomes 1:1 (disabled) - Endbiome 1:1 (inaktiv) + + End at scale + Ende bei Maßstab - - End biomes after voronoi scaling to 1:1. + + End biomes sampled on a scaled grid. - - End biomes 1:4 - Endbiome 1:4 - - - - End biomes sampled at scale 1:4. Note this is just a simple upscale of 1:16. - + + Biome layer 1:4 RIVER + Biomlage 1:4 RIVER - - End biomes 1:16 - Endbiome 1:16 + + Biome layer 1:256 O.TEMP + Biomlage 1:256 O.TEMP - - End biomes with normal sampling at scale 1:16. - + + Climate parameters + Klimaparameter - - End biomes with lossy sampling at scale 1:64. - + + Locate climate extreme + Klimaextrem Lokalisieren - - End biomes 1:64 - Endbiome 1:64 + + Locate biome center + Biomzentrum Lokalisieren - + Spawn Spawnpoint - + Slime chunk - + Surface height Oberflächenhöhe - + Check the approximate surface height at scale 1:4 at a single coordinate. - + First stronghold Erste Festung - + Finds the approxmiate location of the first stronghold (+/-112 blocks). Depends only on the 48-bit seed. - + Stronghold Festung - + Village Dorf - + Abandoned mineshaft Mine - + Desert pyramid Wüstentempel - + In version 1.18+, desert pyramids depend on surface height and may fail to generate near caves/aquifers, rivers and oceans. - + Jungle temple Dschungeltempel - + In version 1.18+, jungle temples depend on surface height and may fail to generate near caves/aquifers, rivers and oceans. - + Swamp hut Sumpfhütte - + Ocean monument Ozeanmonument - + Igloo Iglu - + Woodland mansion Waldanwesen - + In version 1.18+, mansions depend on surface height and may fail to generate near caves/aquifers, rivers and oceans. - + Ocean ruins Ozeanruine - + Shipwreck Schiffswrack - + Buried treasure Vergrabener Schatz - + Buried treasures are always positioned near the center of a chunk rather than a chunk boarder. Make sure the testing area is set accordingly. - + Desert well Wüstenbrunnen - + Pillager outpost Plünderer-Außenposten - + Ancient city Antike Stadt - + Trail ruins Trail Ruins - + Ruined portal (overworld) Portalruine (Oberwelt) - + Ruined portal (nether) Portalruine (Nether) - + Nether fortress Netherfestung - + Bastion remnant Bastionsruine - + End city Endsiedlung - + End gateway Endtransitportal - + Checks only scattered return gateways. Does not include those generated when defeating the dragon. @@ -2629,32 +2609,32 @@ Fortfahren und Überschreiben? Neu - + Disable Deaktivieren - + Enable Aktivieren - + Toggle Umschalten - + Add new condition Neue Bedingung - + Edit condition Bedingung bearbeiten - + Cut %n condition(s) %n Bedingung ausschneiden @@ -2662,8 +2642,8 @@ Fortfahren und Überschreiben? - - + + Copy %n condition(s) %n Bedingung kopieren @@ -2671,7 +2651,7 @@ Fortfahren und Überschreiben? - + Paste %n condition(s) %n Bedingung einfühgen @@ -2679,7 +2659,7 @@ Fortfahren und Überschreiben? - + Remove %n condition(s) %n Bedingung löschen @@ -2915,12 +2895,12 @@ Nur für Strukturen mit region-size = 32 und chunk-gap = 8 [Keine] - + Load seed list Seedliste laden - + Text files (*.txt);;Any files (*) Textdateien (*.txt);;Alle Dateien (*) @@ -2948,6 +2928,11 @@ Nur für Strukturen mit region-size = 32 und chunk-gap = 8 Threads: Threads: + + + Queued progress within the search set + Anstehender Vortschritt in der Durchsuchungsmenge + stop as soon as the next set of matching seeds is found @@ -2974,25 +2959,20 @@ Nur für Strukturen mit region-size = 32 und chunk-gap = 8 Seed: - + incremental Inkrementell - + 48-bit only 48-Bit Teil-Seed - + 48-bit family blocks 48-Bit Seedblöcke - - - Queued progress within search set - Anstehender Vortschritt im Suchraum - Clear results @@ -3000,8 +2980,8 @@ Nur für Strukturen mit region-size = 32 und chunk-gap = 8 - - + + Start search Suche starten @@ -3011,82 +2991,77 @@ Nur für Strukturen mit region-size = 32 und chunk-gap = 8 Bereit - + Failed to load 64-bit seed list from file: "%1" 64-Bit Seedliste konnte nicht geladen werden: "%1" - + Please define some constraints using the "Add" button. Erst Bedingungen mit der "Neu" Taste hinzufügen. - + No seed list file selected. Keine Datei für die Seedliste ausgewählt. - + Search is still running. Suche läuft noch. - + Abort search Suche abbrechen - + Load seed list Seedliste laden - + Text files (*.txt);;Any files (*) Textdateien (*.txt);;Alle Dateien (*) - + Remove selected seed Angewählte Seeds löschen - + Copy selected seed Seed kopieren - + Copy seed list Seedliste kopieren - - <html><head/><body><p>The <b>incremental</b> search checks seeds in numerical order, save for grouping into work items for parallelization. This type of search is best suited for a non-exhaustive search space and with strong biome dependencies. You can restrict this type of search to a value range using the &quot;...&quot; button.</p><p>When searching <b>48-bit only</b>, the search is limited to the seed bases and does not yield matching seeds, but rather checks only the parts of the conditions can be determined from the lower 48-bits. Sessions saved from this search are suitable to be used later with the 48-bit generator to look for matching seeds.</p><p>With <b>48-bit family blocks</b> the search looks for suitable 48-bit seeds first and parallelizes the search through the upper 16-bits. This search type is best suited for exhaustive searches and those with very restrictive structure requirements.</p><p>Load a <b>seed list from a file</b> to search through an existing set of seeds. The seeds should be in decimal ASCII text, 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> - - - - + Done Progressbar Fertig - + Idle Progressbar Bereit - + Running... Progressbar Gestartet... - + Paste %n seed(s) from clipboard %n Seed einfügen @@ -3094,17 +3069,22 @@ Nur für Strukturen mit region-size = 32 und chunk-gap = 8 - + seed list from file... Seedliste aus Datei... - + Help: search types Hilfe: Suchmodus - + + <html><head/><body><p>The <b>incremental</b> search checks seeds in numerical order, except for grouping seeds into work items for parallelization. This is the recommended option for general searches. You can restrict this type of search to a value range using the &quot;...&quot; button.</p><p>When using <b>48-bit only</b>, the search checks partial seeds and will not test the full conditions. Instead it yields seed bases that may satify the conditions without knowing the upper 16-bit of the seed. A session file saved from this search is suitable to be used later with the 48-bit generator to look for matching seeds.</p><p>With <b>48-bit family blocks</b> the search looks for suitable 48-bit seeds first and parallelizes the search through the upper 16-bits. This search type can be a better match for exhaustive searches and those with very restrictive structure requirements.</p><p>Load a <b>seed list from a file</b> to search through an existing set of seeds. The seeds should be in decimal ASCII text, 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> + + + + Maximum number of results reached (%1). Maximale Anzahl von Ergebnissen erreicht (%1). @@ -3154,6 +3134,59 @@ Continue anyway? Trozdem fortfahren? + + Layer + + + 1:1 Voronoi + + + + + 1:4 River Mix + + + + + 1:4 Ocean Mix + + + + + 1:4 Zoom + + + + + 1:16 Swamp River + + + + + 1:16 Shore + + + + + 1:64 Hills + + + + + 1:64 Sunflower + + + + + 1:256 Biome + + + + + 1:256 Bamboo + + + LayerDialog @@ -3232,580 +3265,618 @@ Trozdem fortfahren? Beta Feuchtigkeit - + Grayscale Graustufen - + Shaded biome map Schattierte Biomkarte - + Contours on biomes Höhenlinien auf Biomkarte - + Shaded with contours Schattierte Höhenlinien + + + All octaves + Alle Oktaven + + + + Contribution of the %n most significant octaves out of %1 total. + + Beitrag der signifikantesten Oktave von %1 insgesamt. + Beitrag der %n signifikantesten Oktaven von %1 insgesamt. + + + + + Total contribution: %1 = %2% + Gesamter Beitrag: %1 = %2% + + + + Octave amplitude: %1 + Oktavenamplitude: %1 + + + + Octave lacunarity: %1 = 1/%2 + Oktavenlakunarität: %1 = 1/%2 + MainWindow - + Cubiomes Viewer Cubiomes Viewer - - + + Seed can be an integer or text. Leave empty for a random seed Seed kann eine ganze Zahl oder ein Text sein. Freilassen für eine zufällige Zahl - + seed: Seed: - + Show map for this y-level Karte bei diesem Y-Level anzeigen - + Y: Y: - + Large biomes Große Biome - - + + Minecraft version Minecraft Version - + MC MC - + 256 (Surface) 256 (Oberfläche) - + 128 (Nether Roof) 128 (Nether Decke) - + 62 (Sea Level) 62 (Meeresspiegel) - + 48 - + 32 - + 16 - + 0 - + -16 - + -32 - + -48 - + -64 (Bedrock) - + Press enter to accept Eingabetaste zum übernehmen - + random zufällig - + Search Suche - + + Seeds + Seeds + + + Map controls Kartenbedienung - - + + Map Karte - + Previous seeds Vorheriger Seed - + Help Hilfe - + File Datei - + Edit Bearbeiten - + Layer Ebene - + About Über - + Open shadow seed Shadow Seed öffnen - + Save session... Sitzung speichern... - + Ctrl+S Strg+S - + Load session... Sitzung laden... - + Ctrl+O Strg+O - + Search seed list... Seedliste durchsuchen... - + Load seeds from file for search Durchsuche Seeds aus Datei - + Search full seed space Durchsuche alle Seeds - + Copy seeds from list Seedliste kopieren - + Paste seeds into list Seedliste einfügen - + Quit Beenden - + Add shadow for all seeds Shadow Seed für jeden Listeneintrag hinzufügen - + Advanced world settings... Erweiterte Welteneinstellungen... - + Example filters... Beispielfilter... - + Save filter as preset... Filter als Vorlage speichern... - + Load filter preset... Filtervorlage laden... - + Edit biome colors... Biomfarben editieren... - + Edit map tools... Werkzeuge editieren... - + + Redistribute condition IDs + IDs neu verteilen + + + Biome scales (default) Biommaßstäbe (Standard) - + Edit preferences... Einstellungen editieren... - + Alt+B - + Go to... Gehe zu... - + Ctrl+G Strg+G - + (1.13 - 1.17) O. Temp. 1:256 (1.13 - 1.17) O. Temp. 1:256 - + Alt+O - + (1.13 - 1.17) River Mix 1:4 (1.13 - 1.17) Fluss Mix 1:4 - + Alt+R - + Export biomes as image... Biome als Bild exportieren... - + (1.18+) Temperature (1.18+) Temperatur - + Alt+T - + (1.18+) Humidity (1.18+) Feuchtigkeit - + Alt+H - + (1.18+) Continentalness (1.18+) Kontinentalheit - + Alt+C - + (1.18+) Erosion (1.18+) Erosion - + Alt+E - + (1.18+) Weirdness (1.18+) Verrücktheit - + Alt+W - + (1.18+) Depth (1.18+) Tiefe - + Alt+D - + Structure potential (48-bit) Strukturpotenzial (48-bit) - + Alt+S - + Take screenshot Screenshot aufnehmen - + Ctrl+Shift+S Strg+Shift+S - - - + + + Undock map Karte ausdocken - + Approx. surface height Ungefähre Oberflächenhöhe - + Alt+Y - + Display options... Anzeigeoptionen... - + (Beta 1.7) No beta oceans (Beta 1.7) Keine Beta Meere - + (Beta 1.7) Temperature (Beta 1.7) Temperatur - + (Beta 1.7) Humidity (Beta 1.7) Feuchtigkeit - - Triggers - Auslösungen + + Locations + Standorte - + Biomes Biome - + Structures Strukturen - + Go to Origin Zum Ursprung - + Zoom In Vergrößern - + Zoom Out Verkleinern - + Overworld Oberwelt - + Nether Nether - + End Ende - + Conditions Bedingungen - + Help: Conditions Hilfe: Bedingungen - + <html><head/><body><p>The search conditions define the properties by which potential seeds are filtered.</p><p>Conditions can reference each other to produce relative positional dependencies (indicated with the ID in square brackets [XY]). When a condition passes its check, it usually yields just one location that other conditions can reference. An exception to this are structure conditions with exactly one required instance. In this case, each found structure occurence is examined separately instead. On the other hand, a condition that checks for a structure cluster, will average the position of all occurences and yield a single position.</p><p>Standard biome conditions yield the center of the testing area as they evaluate the area as a whole. To locate the position of a given biome you can use the designated <b>locate</b> filters, or use a spiral iterator to scan an area with a localized condition.</p></body></html> - + Seed generator (48-bit) Seedgenerator (48-bit) - + Help: Seed generator Hilfe: Seedgenerator - + <html><head/><body><p>For some searches, the 48-bit structure seed candidates can be generated without searching, which can vastly reduce the search space that has to be checked.</p><p>The generator mode <b>Auto</b> is recommended for general use, which automatically selects suitable options based on the conditions list.</p><p>The <b>Quad-feature</b> mode produces candidates for quad&#8209;structures that have a uniform distribution of region&#8209;size=32 and chunk&#8209;gap=8, such as swamp huts.</p><p>A perfect <b>Quad-monument</b> structure constellation does not actually exist, but some extremely rare structure seed bases get close, with over 90&#37; of the area within 128 blocks. The generator uses a precomputed list of these seed bases.</p><p>Using a <b>Seed list</b> you can provide a custom set of 48-bit candidates. Optionally, a salt value can be added and the seeds can be region transposed.</p></body></html> - + Matching seeds Passende Seeds - + Help: Matching seeds Hilfe: Passende Seeds - + <html><head/><body><p>The list of seeds acts as a buffer onto which suitable seeds are added when they are found. You can also copy the seed list, or paste seeds into the list. Selecting a seed will open it in the map view.</p></body></html> - + Show %1 %1 anzeigen - + text Seed input type Seed-Eingabetyp Text - + random Seed input type Seed-Eingabetyp zufällig - + Save progress Vortschritt speichern - - + + Session files (*.session *.txt);;Any files (*) Sitzungsdateien (*.session *.txt);;Alle Dateien (*) - + Load progress Vortschritt laden - + Save screenshot Screenshot speichern - + Images (*.png *.jpg *.ppm) Bilder (*.png *.jpg *.ppm) - + Redock map Karte andocken - + The application will need to be restarted before all changes can take effect. Die Anwendung muss neugestartet werden um alle Änderungen wirksam zu machen. @@ -3971,33 +4042,33 @@ Trozdem fortfahren? MapView - - + + Copy tp: Kopiere tp: - + Copy coords: Kopiere Block: - + Copy chunk: Kopiere Chunk: - + Copy region: Kopiere Region: - + Go to coordinates... Koordinaten eingeben... - + Copy seed: Kopiere Seed: @@ -4050,104 +4121,80 @@ Trozdem fortfahren? - + Abandoned Villages in separate biomes (1.10+) - + Two abandoned Villages close together, one in a Plains, the other in a Desert. Works best with the 48-bit family search. - + All the Fish (1.13+) - + A River bordering a Lukewarm Ocean somewhere within 2000 blocks, a combination where all fish variants can spawn. - + Village or Treasure with Portal (1.16+) - + Spawn at a Ruined Portal right beside a Village <b>OR</b> Buried Treasure. - + Speedrunner Village (1.16+) - + Spawn in a Village with a Ruined Portal leading to a Stronghold. Works best with the 48-bit family search. - + Biome Diverity (1.18+) - + A wide range of climates near the origin. (Does not look for any particular biomes.) - + Large Jungle (1.18+) - + A large Jungle biome at the origin. Looks for a suitable climate that primarily supports Jungle variants. - - Large Birch Forest (1.18+) - - - - - A large Birch Forest biome at the origin. - -Looks for a climate that supports Birch Forest variants. Swamps and Meadows can generate in the same climates and are explicitly excluded. - - - - - Large Old Growth Taiga somewhere (1.18+) - - - - - A large Old Growth Taiga biome somewhere within 2500 blocks. - -Searches an area of +/-2500 blocks for a large climate region that primarily supports Old Growth Taiga variants - - - - + New Preset Neue Vorlage - + Preset title: Vorlagenname: @@ -4429,17 +4476,17 @@ Bedingungen fehlen oder sind ungeordnet. Bedingung %1 ist nicht verfügbar nach Minecraft Version %2. - + Biome condition with ID %1 has contradicting flags for include and exclude. Bedingung %1 hat widersprüchliche Inklusionskennungen für Biome. - + Biome condition with ID %1 specifies no biomes. Bedingung %1 gibt keine Biome an. - + Biome condition with ID %1 includes %n biome(s) that do not generate in MC %2. Bedingung %1 gibt %n Biom an, dass nicht in MC %2 generiert. @@ -4447,34 +4494,34 @@ Bedingungen fehlen oder sind ungeordnet. - - Temperature category condition with ID %1 has too many restrictions (%2) for the area (%3 x %4). - Bedingung %1 spezifiziert zu viele (%2) Temperaturkategorieen für die gewählte Region (%3 x %4). + + Temperature category condition with ID %1 has too many restrictions (%2) for the area (%3 x %4 @ scale 1:1024). + Bedingung %1 spezifiziert zu viele (%2) Temperaturkategorieen für die gewählte Region (%3 x %4 @ Maßstab 1:1024). - + Structure condition %1 checks for too many instances (>= 128). Bedingung %1 testet nach zu vielen Strukturinstanzen (>= 128). - + Condition %1 ignores its only location of size 1. Bedingung %1 ignoriert seine einzige Position mit Größe 1. - + Failed to setup search environment: %1 Suchumgebung konnte nicht aufgebaut werden: %1 - + Failed to generate protobases. Protobases konnten nicht angelegt werden. - + Failed to stop %n worker thread(s). Keep waiting for threads to stop? @@ -4488,17 +4535,17 @@ Weiter auf den Stop der Threads warten? SeedTableModel - + seed Seed - + top 16 obere 16 - + lower 48 bit untere 48 Bit @@ -4506,12 +4553,12 @@ Weiter auf den Stop der Threads warten? SpinExclude - + (ignore) (ignorieren) - + (exclude) (exkludieren) @@ -4519,12 +4566,12 @@ Weiter auf den Stop der Threads warten? SpinInstances - + (exclude) (exkludieren) - + (cluster) (gebündelt) @@ -4769,11 +4816,163 @@ Weiter auf den Stop der Threads warten? Bereich - + (%1 sq. chunks) (%1 Chunks) + + TabLocations + + + Form + + + + + Number of samples: + Stichprobenanzahl: + + + + + Idle + Bereit + + + + 1 + + + + + X: + + + + + Sampling strategy: + Stichprobenstategie: + + + + Export... + Export... + + + + Expand all + Alle expandieren + + + + + Analyze + Analysieren + + + + + id + ID + + + + + seed/condition + Seed/Bedingung + + + + + x + X + + + + + z + Z + + + + + distance + Distanz + + + + 512 + + + + + Z: + + + + + Centered on: + Zentriert auf: + + + + Spread (α): + Ausbreitung (α): + + + + Seed(s): + Seed(s): + + + + Current seed + Aktuelle Seed + + + + From matching seeds list + Aus der Ergebnis Seedliste + + + + Lattice points in radial order + Gitterpunkte in radialer Reihenfolge + + + + Square spiral + Quadratische Spirale + + + + Random Gaussian samples + Aus einer Gaußische Verteilung + + + + Stop + Stop + + + + Text files (*.txt *csv);;Any files (*) + Textdateien (*.txt *csv);;Alle Dateien (*) + + + + Export locations + Standorte exportieren + + + + Failed to open file for export: +"%1" + Exportdatei konnte nicht geöffnet werden: +"%1" + + TabStructures @@ -4983,46 +5182,46 @@ Weiter auf den Stop der Threads warten? - + Seed(s): Seed(s): - - + + Examine how the conditions are evaluated. + + + + + seed Seed - - + + condition Bedingung - - + + x X - - + + z Z - - Analyze the search condition triggers. - Analyse der Auslösung von Suchbedingungen. - - - + Current seed Aktuelle Seed - + From matching seeds list Aus der Ergebnis Seedliste @@ -5038,28 +5237,28 @@ Weiter auf den Stop der Threads warten? - + Analyze Analyse - - + + Stop Stop - + Export trigger analysis Export der Auslösung der Bedingungen - + Text files (*.txt *csv);;Any files (*) Textdateien (*.txt *csv);;Alle Dateien (*) - + Failed to open file for export: "%1" Exportdatei konnte nicht geöffnet werden: diff --git a/src/conditiondialog.cpp b/src/conditiondialog.cpp index 472e12e..419b459 100644 --- a/src/conditiondialog.cpp +++ b/src/conditiondialog.cpp @@ -46,15 +46,10 @@ ConditionDialog::ConditionDialog(FormConditions *parent, MapView *mapview, Confi QString mcs = tr("MC %1", "Minecraft version").arg(p_mcs ? p_mcs : "?"); ui->labelMC->setText(mcs); -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) - ui->textEditLua->setTabStopWidth(QFontMetrics(ui->textEditLua->font()).width(" ") * 4); -#else - ui->textEditLua->setTabStopDistance(QFontMetricsF(ui->textEditLua->font()).horizontalAdvance(" ") * 4); -#endif - + ui->textEditLua->setTabStopWidth(txtWidth(ui->textEditLua->font(), " ")); ui->lineSummary->setMinimumWidth( ui->lineSummary->minimumSizeHint().width() + - QFontMetrics(ui->lineSummary->font()).horizontalAdvance('#') * 26 + txtWidth(ui->lineSummary->font()) * 26 ); // prevent bold font of group box title getting inherited @@ -125,17 +120,21 @@ ConditionDialog::ConditionDialog(FormConditions *parent, MapView *mapview, Confi ui->comboCat->addItem(tr("Select category")); ui->comboCat->insertSeparator(1); - ui->comboCat->addItem(getPix("helper"), tr("Algorithm helpers"), CAT_HELPER); - ui->comboCat->addItem(getPix("quad"), tr("Quad-structure"), CAT_QUAD); - ui->comboCat->addItem(getPix("stronghold"), tr("Structures"), CAT_STRUCT); ui->comboCat->addItem(getPix("overworld"), tr("Biomes"), CAT_BIOMES); - ui->comboCat->addItem(getPix("nether"), tr("Nether biomes"), CAT_NETHER); - ui->comboCat->addItem(getPix("the_end"), tr("End biomes"), CAT_END); + ui->comboCat->addItem(getPix("stronghold"), tr("Structures"), CAT_STRUCT); + ui->comboCat->addItem(getPix("quad"), tr("Quad-structure"), CAT_QUAD); + ui->comboCat->addItem(getPix("helper"), tr("Algorithm helpers"), CAT_HELPER); ui->comboCat->addItem(getPix("slime"), tr("Other"), CAT_OTHER); int fmh = ui->comboCat->fontMetrics().height() + 8; ui->comboCat->setIconSize(QSize(fmh, fmh)); ui->comboType->setIconSize(QSize(fmh, fmh)); + ui->comboScale->addItem("1:1", QVariant::fromValue(1)); + ui->comboScale->addItem("1:4", QVariant::fromValue(4)); + ui->comboScale->addItem("1:16", QVariant::fromValue(16)); + ui->comboScale->addItem("1:64", QVariant::fromValue(64)); + ui->comboScale->addItem("1:256", QVariant::fromValue(256)); + for (int i = 0; i < 256; i++) { QString bname = getBiomeDisplay(wi.mc, i); @@ -302,8 +301,9 @@ ConditionDialog::ConditionDialog(FormConditions *parent, MapView *mapview, Confi ui->checkSkipRef->setChecked(false); ui->radioSquare->setChecked(true); ui->checkRadius->setChecked(false); - ui->lineCoverage->setText("100"); + ui->lineCoverage->setText("50"); ui->lineConfidence->setText("95"); + ui->comboScale->setCurrentIndex(1); onCheckStartChanged(false); on_comboClimatePara_currentIndexChanged(0); @@ -323,22 +323,16 @@ ConditionDialog::ConditionDialog(FormConditions *parent, MapView *mapview, Confi ui->comboLua->setCurrentIndex(ui->comboLua->findData(QVariant::fromValue(cond.hash))); ui->comboCat->setCurrentIndex(ui->comboCat->findData(ft.cat)); - for (int i = 0; i < ui->comboType->count(); i++) - { - int type = ui->comboType->itemData(i, Qt::UserRole).toInt(); - if (type == cond.type) - { - ui->comboType->setCurrentIndex(i); - break; - } - } - + ui->comboType->setCurrentIndex(ui->comboType->findData(cond.type)); ui->comboRelative->setCurrentIndex(initindex); on_comboRelative_activated(initindex); ui->textEditLua->document()->setModified(false); if (cond.step) + { ui->lineSpiralStep->setText(QString::number(cond.step)); + ui->comboScale->setCurrentIndex(ui->comboScale->findData(QVariant::fromValue(cond.step))); + } ui->comboMatchBiome->insertItem(0, getBiomeDisplay(wi.mc, cond.biomeId), QVariant::fromValue(cond.biomeId)); ui->comboMatchBiome->setCurrentIndex(0); @@ -349,6 +343,7 @@ ConditionDialog::ConditionDialog(FormConditions *parent, MapView *mapview, Confi ui->comboMinMax->setCurrentIndex((cond.minmax & Condition::E_LOCATE_MAX) ? 1 : 0); ui->lineMin->setText((cond.minmax & Condition::E_TEST_LOWER) ? QString::number(cond.vmin) : ""); ui->lineMax->setText((cond.minmax & Condition::E_TEST_UPPER) ? QString::number(cond.vmax) : ""); + ui->checkInvertRange->setChecked(cond.flags & Condition::FLG_INVERT); updateMode(); @@ -361,9 +356,9 @@ ConditionDialog::ConditionDialog(FormConditions *parent, MapView *mapview, Confi ui->checkApprox->setChecked(cond.flags & Condition::FLG_APPROX); ui->checkMatchAny->setChecked(cond.flags & Condition::FLG_MATCH_ANY); - ui->lineCoverage->setText(QString::number(cond.converage ? cond.converage * 100 : 100)); - ui->lineConfidence->setText(QString::number(cond.confidence ? cond.confidence * 100 : 95)); ui->checkSamplePos->setChecked(cond.count == 1); + ui->lineCoverage->setText(QString::number(cond.converage ? cond.converage * 100 : 50)); + ui->lineConfidence->setText(QString::number(cond.confidence ? cond.confidence * 100 : 95)); int i, n = ui->comboY->count(); for (i = 0; i < n; i++) @@ -589,7 +584,7 @@ void ConditionDialog::updateMode() { ui->stackedWidget->setCurrentWidget(ui->pageBiomeCenter); } - else if (ft.cat == CAT_BIOMES || ft.cat == CAT_NETHER || ft.cat == CAT_END) + else if (ft.cat == CAT_BIOMES) { ui->stackedWidget->setCurrentWidget(ui->pageBiomes); ui->checkApprox->setEnabled(wi.mc <= MC_1_17 || ft.grid == 4); @@ -654,8 +649,8 @@ void ConditionDialog::updateMode() QString lowtip = tr("Lower bound (inclusive)"); QString uptip = tr("Upper bound (inclusive)"); - if (ft.grid > 1) - loc += " " + tr("(sampled on a grid of scale 1:%1)").arg(ft.grid); + //if (ft.grid > 1) + // loc += " " + tr("(sampled on a grid of scale 1:%1)").arg(ft.grid); ui->groupBoxPosition->setTitle(loc); ui->radioSquare->setToolTip(areatip); @@ -671,24 +666,59 @@ void ConditionDialog::updateMode() textDescription->setText(QApplication::translate("Filter", ft.description)); } +static QString layerText(int layerId) +{ + switch (layerId) + { + case L_VORONOI_1: return QApplication::translate("Layer", "1:1 Voronoi"); + case L_RIVER_MIX_4: return QApplication::translate("Layer", "1:4 River Mix"); + case L_OCEAN_MIX_4: return QApplication::translate("Layer", "1:4 Ocean Mix"); + case L_ZOOM_4: return QApplication::translate("Layer", "1:4 Zoom"); + case L_SWAMP_RIVER_16: return QApplication::translate("Layer", "1:16 Swamp River"); + case L_SHORE_16: return QApplication::translate("Layer", "1:16 Shore"); + case L_HILLS_64: return QApplication::translate("Layer", "1:64 Hills"); + case L_SUNFLOWER_64: return QApplication::translate("Layer", "1:64 Sunflower"); + case L_BIOME_256: return QApplication::translate("Layer", "1:256 Biome"); + case L_BAMBOO_256: return QApplication::translate("Layer", "1:256 Bamboo"); + } + return ""; +} + void ConditionDialog::updateBiomeSelection() { - int filterindex = ui->comboType->currentData().toInt(); - const FilterInfo &ft = g_filterinfo.list[filterindex]; + int filter = ui->comboType->currentData().toInt(); + int scale = ui->comboScale->currentData().toInt(); + const FilterInfo &ft = g_filterinfo.list[filter]; // clear tool tips for (const auto& it : biomecboxes) it.second->setToolTip(""); + ui->labelBiomeScale->setText(tr("Sampling scale:")); + ui->comboScale->setEnabled(false); + for (int i = 0, n = ui->comboScale->count(); i < n; i++) + { + ui->comboScale->setItemText(i, QString::asprintf("1:%d", 1 << (i*2))); + ui->comboScale->setItemData(i, QVariant::Invalid, Qt::UserRole-1); + } + // ui->comboScale->setItemData(0, false, Qt::UserRole-1); // disable voronoi + std::vector available; - if (ft.cat == CAT_NETHER || ft.cat == CAT_END) + if (filter == F_BIOME_NETHER || filter == F_BIOME_END) { + ui->comboScale->setEnabled(true); + if (filter == F_BIOME_END) + { // disable 1:256 end biomes + int idx256 = ui->comboScale->findData(QVariant::fromValue(256)); + ui->comboScale->setItemText(idx256, QString("1:256 ") + WARNING_CHAR); + ui->comboScale->setItemData(idx256, false, Qt::UserRole-1); + } for (int i = 0; i < 256; i++) if (getDimension(i) == ft.dim) available.push_back(i); } - if (filterindex == F_BIOME_256_OTEMP) + else if (filter == F_BIOME_256_OTEMP) { available.push_back(warm_ocean); available.push_back(lukewarm_ocean); @@ -698,20 +728,26 @@ void ConditionDialog::updateBiomeSelection() } else if (ft.cat == CAT_BIOMES && wi.mc > MC_B1_7 && wi.mc <= MC_1_17) { - //int scale = ui->comboScale->currentData().toInt(); - //ui->comboScale->addItem(tr("")); - - int layerId = ft.layer; - if (layerId == 0) + int layerId = L_RIVER_MIX_4; + if (filter != F_BIOME_4_RIVER) { - Generator tmp; - setupGenerator(&tmp, wi.mc, 0); - const Layer *l = getLayerForScale(&tmp, ft.grid); - if (l) - layerId = l - tmp.ls.layers; + ui->labelBiomeScale->setText(tr("Generation layer:")); + ui->comboScale->setEnabled(true); + for (int i = 0, n = ui->comboScale->count(); i < n; i++) + { + Generator tmp; + setupGenerator(&tmp, wi.mc, 0); + int s = 1 << 2*i; + if (const Layer *l = getLayerForScale(&tmp, s)) + { + QString txt = layerText(l - tmp.ls.layers); + if (!txt.isEmpty()) + ui->comboScale->setItemText(i, txt); + if (scale == s) + layerId = l - tmp.ls.layers; + } + } } - if (layerId <= 0 || layerId >= L_NUM) - return; // error for (const auto& it : biomecboxes) { @@ -723,7 +759,7 @@ void ConditionDialog::updateBiomeSelection() if (mL || mM) { available.push_back(it.first); - if (ft.layer != L_VORONOI_1) + if (layerId != L_VORONOI_1) { QString tip = tr("Generates any of:"); for (int j = 0; j < 64; j++) @@ -747,6 +783,7 @@ void ConditionDialog::updateBiomeSelection() } else if (ft.cat == CAT_BIOMES && ft.dim == DIM_OVERWORLD) { + ui->comboScale->setEnabled(true); for (const auto& it : biomecboxes) { if (isOverworld(wi.mc, it.first)) @@ -860,7 +897,7 @@ int ConditionDialog::warnIfBad(Condition cond) } else if (cond.type == F_BIOME_CENTER || cond.type == F_BIOME_CENTER_256) { - int s = ft.pow2; + int s = cond.type == F_BIOME_CENTER ? 2 : 8; int w = (cond.x2 >> s) - (cond.x1 >> s) + 1; int h = (cond.z2 >> s) - (cond.z1 >> s) + 1; if ((unsigned int)(w * h) < cond.count * cond.biomeSize) @@ -895,6 +932,40 @@ int ConditionDialog::warnIfBad(Condition cond) QMessageBox::Ok | QMessageBox::Cancel); } } + if (cond.type == F_BIOME_SAMPLE) + { + if (cond.biomeToFind == 0 && cond.biomeToFindM == 0) + { + return warn(this, tr("No Allowed Biomes"), + tr("The set of allowed biomes is empty, which can never " + "be satisfied. Please include some biomes for the required " + "proportion."), + QMessageBox::Cancel); + } + } + } + else if (ft.cat == CAT_QUAD) + { + if (!cond.relative) + { + enum { AFTRAD = 50, AFKMIN = 420, AFKMAX = 488 }; // all quad-structures have a region offset between these values + bool ok = true; + if (cond.rmax > 0) + ok = cond.rmax > AFTRAD; + else if (cond.x2 - cond.x1 < 512 - (AFKMAX - AFKMIN)) + ok &= (cond.x1 & 511) < AFKMAX && (cond.x1 & 511) > AFKMIN - (cond.x2 - cond.x1); + else if (cond.z2 - cond.z1 < 512 - (AFKMAX - AFKMIN)) + ok &= (cond.z1 & 511) < AFKMAX && (cond.z1 & 511) > AFKMIN - (cond.z2 - cond.z1); + if (!ok) + { + return warn(this, tr("Bad Area for Quad-Structure"), + tr("The selected area does not contain a range where a " + "quad-structure can generate." + "\n\n" + "Continue anyway?"), + QMessageBox::Ok | QMessageBox::Cancel); + } + } } return QMessageBox::Ok; } @@ -970,7 +1041,15 @@ void ConditionDialog::onAccept() c.y = ui->comboY->currentText().section(' ', 0, 0).toInt(); - c.step = ui->lineSpiralStep->text().toUShort(); + c.flags = 0; + if (ui->checkApprox->isChecked()) + c.flags |= Condition::FLG_APPROX; + if (ui->checkMatchAny->isChecked()) + c.flags |= Condition::FLG_MATCH_ANY; + if (ui->comboHeightRange->currentIndex() == 0) + c.flags |= Condition::FLG_IN_RANGE; + if (ui->checkInvertRange->isChecked()) + c.flags |= Condition::FLG_INVERT; if (ui->stackedWidget->currentWidget() == ui->pageBiomes) { @@ -999,6 +1078,8 @@ void ConditionDialog::onAccept() c.count = ui->checkSamplePos->isChecked() ? 1 : 0; c.converage = ui->lineCoverage->text().toFloat() / 100.0; c.confidence = ui->lineConfidence->text().toFloat() / 100.0; + if (c.type == F_BIOME_END && c.step > 64) + c.step = 64; } if (ui->stackedWidget->currentWidget() == ui->pageBiomeCenter) { @@ -1033,14 +1114,10 @@ void ConditionDialog::onAccept() c.count += cnt; } } - - c.flags = 0; - if (ui->checkApprox->isChecked()) - c.flags |= Condition::FLG_APPROX; - if (ui->checkMatchAny->isChecked()) - c.flags |= Condition::FLG_MATCH_ANY; - if (ui->comboHeightRange->currentIndex() == 0) - c.flags |= Condition::FLG_IN_RANGE; + if (ui->stackedWidget->currentWidget() == ui->pageSpiral) + { + c.step = ui->lineSpiralStep->text().toUShort(); + } c.varflags = c.varstart = 0; if (ui->checkStartPieces->isChecked()) @@ -1068,11 +1145,60 @@ void ConditionDialog::onAccept() close(); } +void ConditionDialog::on_comboCat_currentIndexChanged(int) +{ + int cat = ui->comboCat->currentData().toInt(); + ui->comboType->setEnabled(cat != CAT_NONE); + ui->comboType->clear(); + + int slot = 0; + ui->comboType->insertItem(slot, tr("Select type"), QVariant::fromValue((int)F_SELECT)); + ui->comboType->insertSeparator(++slot); + + const FilterInfo *ft_list[FILTER_MAX] = {}; + const FilterInfo *ft; + + for (int i = 1; i < FILTER_MAX; i++) + { + ft = &g_filterinfo.list[i]; + if (ft->cat == cat) + ft_list[ft->disp] = ft; + } + + for (int i = 1; i < FILTER_MAX; i++) + { + ft = ft_list[i]; + if (!ft) + continue; + slot++; + QVariant vidx = QVariant::fromValue((int)(ft - g_filterinfo.list)); + QString txt = QApplication::translate("Filter", ft->name); + if (ft->icon) + ui->comboType->insertItem(slot, getPix(ft->icon), txt, vidx); + else + ui->comboType->insertItem(slot, txt, vidx); + + if (wi.mc < ft->mcmin || wi.mc > ft->mcmax) + ui->comboType->setItemData(slot, false, Qt::UserRole-1); // deactivate + if (ft == g_filterinfo.list + F_FORTRESS) + ui->comboType->insertSeparator(slot++); + if (ft == g_filterinfo.list + F_ENDCITY) + ui->comboType->insertSeparator(slot++); + } + + updateMode(); +} + void ConditionDialog::on_comboType_activated(int) { updateMode(); } +void ConditionDialog::on_comboScale_activated(int) +{ + updateMode(); +} + void ConditionDialog::on_comboRelative_activated(int) { QPalette pal; @@ -1117,10 +1243,10 @@ void ConditionDialog::on_buttonAreaInfo_clicked() "example a centered square with side 3 will go from -2 to 1 for both " "the X and Z axes." "

" - "Important to note is that some filters have a scaling associated with " - "them. This means the condition only checks on a grid with that spacing. " - "An area with a range from -21 to 21 at scale 1:16 may effectively be " - "expanded to -32 to 31, and get sampled at -32, -16, 0 and 16." + "Some filters have a scaling associated with them. This means the " + "condition only checks on a grid with that spacing. An area with a " + "range from -21 to 21 at scale 1:16 may effectively be expanded to " + "-32 to 31, and get sampled at -32, -16, 0 and 16." "

" )); mb.exec(); @@ -1174,50 +1300,6 @@ void ConditionDialog::on_ConditionDialog_finished(int result) item = 0; } -void ConditionDialog::on_comboCat_currentIndexChanged(int) -{ - int cat = ui->comboCat->currentData().toInt(); - ui->comboType->setEnabled(cat != CAT_NONE); - ui->comboType->clear(); - - int slot = 0; - ui->comboType->insertItem(slot, tr("Select type"), QVariant::fromValue((int)F_SELECT)); - ui->comboType->insertSeparator(++slot); - - const FilterInfo *ft_list[FILTER_MAX] = {}; - const FilterInfo *ft; - - for (int i = 1; i < FILTER_MAX; i++) - { - ft = &g_filterinfo.list[i]; - if (ft->cat == cat) - ft_list[ft->disp] = ft; - } - - for (int i = 1; i < FILTER_MAX; i++) - { - ft = ft_list[i]; - if (!ft) - continue; - slot++; - QVariant vidx = QVariant::fromValue((int)(ft - g_filterinfo.list)); - QString txt = QApplication::translate("Filter", ft->name); - if (ft->icon) - ui->comboType->insertItem(slot, getPix(ft->icon), txt, vidx); - else - ui->comboType->insertItem(slot, txt, vidx); - - if (wi.mc < ft->mcmin || wi.mc > ft->mcmax) - ui->comboType->setItemData(slot, false, Qt::UserRole-1); // deactivate - if (ft == g_filterinfo.list + F_FORTRESS) - ui->comboType->insertSeparator(slot++); - if (ft == g_filterinfo.list + F_ENDCITY) - ui->comboType->insertSeparator(slot++); - } - - updateMode(); -} - void ConditionDialog::onCheckStartChanged(int checked) { // synchronize stat piece checkboxes ui->checkStartPieces->setChecked(checked); @@ -1574,5 +1656,3 @@ void ConditionDialog::on_comboY2_currentTextChanged(const QString &text) if (ui->comboY->currentText() != text) ui->comboY->setCurrentText(text); } - - diff --git a/src/conditiondialog.h b/src/conditiondialog.h index 87ea0e2..9ee7ee6 100644 --- a/src/conditiondialog.h +++ b/src/conditiondialog.h @@ -80,7 +80,7 @@ class CoordEdit : public QLineEdit { QSize size = QLineEdit::minimumSizeHint(); QFontMetrics fm(font()); - size.setWidth(size.width() + fm.horizontalAdvance("-30000000")); + size.setWidth(size.width() + txtWidth(fm, "-30000000")); return size; } }; @@ -200,7 +200,9 @@ class ConditionDialog : public QDialog void setCond(QListWidgetItem *item, Condition cond, int modified); private slots: + void on_comboCat_currentIndexChanged(int); void on_comboType_activated(int); + void on_comboScale_activated(int); void on_comboRelative_activated(int); @@ -220,8 +222,6 @@ private slots: void on_ConditionDialog_finished(int result); - void on_comboCat_currentIndexChanged(int); - void onCheckStartChanged(int state); void onClimateLimitChanged(); diff --git a/src/conditiondialog.ui b/src/conditiondialog.ui index 5b5d9b5..e47b520 100644 --- a/src/conditiondialog.ui +++ b/src/conditiondialog.ui @@ -395,7 +395,7 @@ QPushButton:hover { 0 - 1 + 5 @@ -467,72 +467,17 @@ QPushButton:hover { Biomes - - - - true + + + + Y: - - 12 + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 256 (Surface) - - - - - 128 (Nether Roof) - - - - - 62 (Sea Level) - - - - - 48 - - - - - 32 - - - - - 16 - - - - - 0 - - - - - -16 - - - - - -32 - - - - - -48 - - - - - -64 (Bedrock) - - - + true @@ -549,7 +494,7 @@ QPushButton:hover { - + @@ -574,19 +519,6 @@ QPushButton:hover { - - - - Qt::Horizontal - - - - 0 - 0 - - - - @@ -596,7 +528,7 @@ QPushButton:hover { - 0 + 1 @@ -628,6 +560,13 @@ QPushButton:hover { + + + + Biome scale: + + + @@ -641,13 +580,6 @@ QPushButton:hover { - - - - Biome scale: - - - @@ -672,13 +604,19 @@ QPushButton:hover { + + Proportion of the area that has to be of the included biomes + - Coverage (%): + Required coverage (%): + + Statistical confidence that the coverage has been reached + Confidence (%): @@ -686,26 +624,96 @@ QPushButton:hover { + + Instead of estimating the center of the allowed biome area, +yield each sampled position individually + - Yield positions + Yield individual samples - + + + Proportion of the area that has to be of the included biomes + + - + + + Statistical confidence that the coverage has been reached + + - - - Sample at height (Y): + + + true + + + 12 + + + 256 (Surface) + + + + + 128 (Nether Roof) + + + + + 62 (Sea Level) + + + + + 48 + + + + + 32 + + + + + 16 + + + + + 0 + + + + + -16 + + + + + -32 + + + + + -48 + + + + + -64 (Bedrock) + + @@ -1115,43 +1123,50 @@ QPushButton:hover { Locate climate minimum/maximum - - - - If value is in range: + + + + <html><head/><body><p>Lower bound (inclusive)</p></body></html> + + + -Infinity - - + + - Climate parameter: + Generate up to octave: - - - - - Monospace - + + + + Qt::Vertical - + + + 20 + 252 + + + - - + + + + Only match if value is outside the given range + - - + Invert range - - - - <html><head/><body><p>Lower bound (inclusive)</p></body></html> - - - -Infinity + + + + Yield position of: @@ -1165,30 +1180,21 @@ QPushButton:hover { - - - - - - - Qt::Vertical - - - - 20 - 252 - + + + + Climate parameter: - + - - + + - Generate up to octave: + If value is in range: - + @@ -1202,10 +1208,22 @@ QPushButton:hover { - - + + + + + - Yield position of: + - + + + + + + + + Monospace + @@ -1799,6 +1817,11 @@ QPushButton:hover { + + CoordEdit + QLineEdit +
src/conditiondialog.h
+
Collapsible QWidget @@ -1815,11 +1838,6 @@ QPushButton:hover { QPlainTextEdit
src/scripts.h
- - CoordEdit - QLineEdit -
src/conditiondialog.h
-
comboCat diff --git a/src/formconditions.cpp b/src/formconditions.cpp index c92dcb7..0391c6e 100644 --- a/src/formconditions.cpp +++ b/src/formconditions.cpp @@ -39,7 +39,7 @@ void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem& option, const QWidget *widget = option.widget; QStyle *style = widget ? widget->style() : QApplication::style(); - int tabwidth = option.fontMetrics.horizontalAdvance('#') * 32; + int tabwidth = txtWidth(option.fontMetrics) * 32; QRect rect = opt.rect; opt.rect.setWidth(tabwidth); @@ -463,6 +463,7 @@ void FormConditions::addItemCondition(QListWidgetItem *item, Condition cond, int if (modified) emit changed(); + updateSensitivity(); } void FormConditions::on_listConditions_indexesMoved(const QModelIndexList &) diff --git a/src/formsearchcontrol.cpp b/src/formsearchcontrol.cpp index ae5d6c4..d7ceb57 100644 --- a/src/formsearchcontrol.cpp +++ b/src/formsearchcontrol.cpp @@ -5,6 +5,7 @@ #include "search.h" #include "rangedialog.h" #include "message.h" +#include "util.h" #include "cubiomes/util.h" @@ -167,8 +168,8 @@ bool FormSearchControl::event(QEvent *e) if (e->type() == QEvent::LayoutRequest) { QFontMetrics fm = QFontMetrics(ui->results->font()); - ui->results->setColumnWidth(SeedTableModel::COL_SEED, fm.horizontalAdvance(QString(24, '#'))); - ui->results->setColumnWidth(SeedTableModel::COL_TOP16, fm.horizontalAdvance(QString(12, '#'))); + ui->results->setColumnWidth(SeedTableModel::COL_SEED, txtWidth(fm, QString(24, '#'))); + ui->results->setColumnWidth(SeedTableModel::COL_TOP16, txtWidth(fm, QString(12, '#'))); ui->results->verticalHeader()->setDefaultSectionSize(fm.height()); } return QWidget::event(e); @@ -615,15 +616,24 @@ void FormSearchControl::onBufferTimeout() int FormSearchControl::searchResultsAdd(std::vector seeds, bool countonly) { + if (seeds.empty()) + return 0; const Config& config = parent->config; - int ns = model->seeds.size(); - int n = ns; + int n = model->seeds.size(); + int nold = n; + bool discarded = false; + if (n >= config.maxMatching) - return 0; - if ((ssize_t)seeds.size() + n > config.maxMatching) + { + sthread.stop(); + discarded = true; + } + if (n + (ssize_t)seeds.size() > config.maxMatching) + { + sthread.stop(); + discarded = true; seeds.resize(config.maxMatching - n); - if (seeds.empty()) - return 0; + } QSet current; current.reserve(n + seeds.size()); @@ -635,13 +645,11 @@ int FormSearchControl::searchResultsAdd(std::vector seeds, bool counto { if (current.contains(s)) continue; - if (countonly) + if (!countonly) { - n++; - continue; + current.insert(s); + newseeds.append(s); } - current.insert(s); - newseeds.append(s); n++; } if (!newseeds.empty()) @@ -650,15 +658,23 @@ int FormSearchControl::searchResultsAdd(std::vector seeds, bool counto model->insertSeeds(newseeds); ui->results->setSortingEnabled(true); } - if (countonly == false && n >= config.maxMatching) - { - stopSearch(); - warn(this, tr("Maximum number of results reached (%1).").arg(config.maxMatching)); - } - int addcnt = n - ns; + int addcnt = n - nold; if (ui->checkStop->isChecked() && addcnt) - stopSearch(); + sthread.stop(); + + if (!countonly && discarded) + { + // guard against recursive calls, which can occur when the + // eventloop is continued in the warning message dialog + thread_local bool warn_active = false; + if (!warn_active) + { + warn_active = true; + warn(this, tr("Maximum number of results reached (%1).").arg(config.maxMatching)); + warn_active = false; + } + } if (addcnt) emit resultsAdded(addcnt); diff --git a/src/headless.cpp b/src/headless.cpp index 139ffe7..8186aca 100644 --- a/src/headless.cpp +++ b/src/headless.cpp @@ -144,10 +144,11 @@ void Headless::run() resultstream.flush(); sthread.start(); + elapsed.start(); if (resultfile.isOpen()) { - qOut() << "\n\n\n\n\n\n"; + qOut() << "\n\n\n\n\n\n\n"; qOut().flush(); timer.start(250); } @@ -174,7 +175,6 @@ void Headless::searchFinish(bool done) emit finished(); } - void Headless::progressTimeout() { QString status; @@ -189,6 +189,7 @@ void Headless::progressTimeout() qreal perc = (qreal) prog / end; int cols = floor(perc * (width - 4) + 1e-6); + qint64 sec = elapsed.elapsed() / 1000; QStringList l; l += QString(" Found matching seeds:%1 ").arg(results.size(), width-23); @@ -196,6 +197,7 @@ void Headless::progressTimeout() l += QString(" Progress:%1 ").arg(QString("%1 / %2 : %3%").arg(prog).arg(end).arg(100*perc, 5, 'f', 2), width-11); l += QString(" [%1%2] ").arg("", cols, '#').arg("", width-cols-4, '-'); l += QString(" %1").arg(status, 1-width); + l += QString::asprintf(" %d:%02d:%02d", (int)(sec / 3600), (int)(sec / 60) % 60, (int)(sec % 60)); l += ""; qOut() << "\e[999D\e[" << l.size() << "A"; diff --git a/src/headless.h b/src/headless.h index 34abf9e..40b5e6c 100644 --- a/src/headless.h +++ b/src/headless.h @@ -4,6 +4,7 @@ #include "searchthread.h" #include #include +#include #include class Headless : public QThread @@ -33,6 +34,7 @@ public slots: QFile resultfile; QTextStream resultstream; QTimer timer; + QElapsedTimer elapsed; }; #endif // HEADLESS_H diff --git a/src/layerdialog.cpp b/src/layerdialog.cpp index aa23d24..df01123 100644 --- a/src/layerdialog.cpp +++ b/src/layerdialog.cpp @@ -79,12 +79,12 @@ bool getLayerOptionInfo(LayerOptInfo *info, int mode, int disp, WorldInfo wi) else { txt += QString("%1..").arg(QChar(0x03A3)); - txt += QString::asprintf("%d%c 1:%-5.0f x%.6f", idx, ab?'B':'A', 1.0/l, a); + txt += QString::asprintf("%d%c 1:%-5.0f x%.6f", idx, ab?'B':'A', 4/l, a); tip += QApplication::translate("LayerDialog", "Contribution of the %n most significant octaves out of %1 total.", "", disp).arg(2*noct); } tip += "\n" + QApplication::translate("LayerDialog", "Total contribution: %1 = %2%").arg(ampsum).arg(100 * ampsum / amptot, 0, 'f', 1); tip += "\n" + QApplication::translate("LayerDialog", "Octave amplitude: %1").arg(a); - tip += "\n" + QApplication::translate("LayerDialog", "Octave lacunarity: %1 = 1/%2").arg(l).arg(1.0/l); + tip += "\n" + QApplication::translate("LayerDialog", "Octave lacunarity: %1 = 1/%2").arg(l).arg(4/l); } if (info) { @@ -134,8 +134,8 @@ LayerDialog::LayerDialog(QWidget *parent, WorldInfo wi) if (!getLayerOptionInfo(&info, i, j, wi)) break; QString s = info.summary.leftJustified(24); - if (j < 9) - s += "\tALT+"+QString::number(j+1); + if (j <= 9) + s += "\tALT+"+QString::number(j); combo[i]->addItem(s); combo[i]->setItemData(combo[i]->count()-1, info.tooltip, Qt::ToolTipRole); } diff --git a/src/main.cpp b/src/main.cpp index a5c159f..7eeba01 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,7 +29,6 @@ int getStructureConfig_override(int stype, int mc, StructureConfig *sconf) int main(int argc, char *argv[]) { - initBiomes(); initBiomeColors(g_biomeColors); initBiomeTypeColors(g_tempsColors); @@ -58,7 +57,7 @@ int main(int argc, char *argv[]) resultspath = argv[i] + 6; else if (strncmp(argv[i], "--out", 5) == 0 && i+1 < argc) resultspath = argv[++i]; - else + else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) usage = true; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2d73131..dde628b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -120,10 +120,10 @@ MainWindow::MainWindow(QString sessionpath, QString resultspath, QWidget *parent act->setActionGroup(grp); } connect(mapView, &MapView::layerChange, this, &MainWindow::onActionBiomeLayerSelect); - for (int i = 0; i < 9; i++) + for (int i = 0; i <= 9; i++) { QAction *act = new QAction(this); - act->setShortcut(QKeySequence(Qt::ALT+Qt::Key_1+i)); + act->setShortcut(QKeySequence(Qt::ALT+Qt::Key_0+i)); act->setEnabled(true); connect(act, &QAction::triggered, [=](){ this->onActionBiomeLayerSelect(lopt.mode, i); @@ -187,7 +187,7 @@ MainWindow::MainWindow(QString sessionpath, QString resultspath, QWidget *parent saction[D_GRID]->setChecked(true); - ui->splitterMap->setSizes(QList({6500, 10000})); + ui->splitterMap->setSizes(QList({6800, 10000})); ui->splitterSearch->setSizes(QList({1000, 3000})); ui->splitterSeeds->setSizes(QList({500, 2500})); @@ -780,6 +780,27 @@ void MainWindow::on_actionOpenShadow_triggered() } } +void MainWindow::on_actionRedistribute_triggered() +{ + QVector conds = formCond->getConditions(); + if (!conds.empty()) + { + QMap ids; + for (int i = 0, n = conds.size(); i < n; i++) + ids.insert(conds[i].save, ids.size()+1); + for (int i = 0, n = conds.size(); i < n; i++) + if (conds[i].relative && !ids.contains(conds[i].relative)) + ids.insert(conds[i].relative, ids.size()+1); + formCond->on_buttonRemoveAll_clicked(); + for (Condition& c : conds) + { + c.save = ids[c.save]; + c.relative = ids[c.relative]; + formCond->addItemCondition(NULL, c, 1); + } + } +} + void MainWindow::on_actionToolbarConfig_triggered() { MapToolsDialog *dialog = new MapToolsDialog(this); @@ -1194,4 +1215,3 @@ void MainWindow::onDockFloating(bool floating) ui->actionDock->setText(tr("Undock map")); } } - diff --git a/src/mainwindow.h b/src/mainwindow.h index 027d6c6..1fae6dd 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -96,6 +96,7 @@ private slots: void on_actionCopy_triggered(); void on_actionPaste_triggered(); void on_actionAddShadow_triggered(); + void on_actionRedistribute_triggered(); void on_actionExtGen_triggered(); void on_actionExportImg_triggered(); void on_actionScreenshot_triggered(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 44f22ee..d0ab237 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -435,6 +435,8 @@ QToolButton:checked { + + @@ -745,6 +747,11 @@ QToolButton:checked { (Beta 1.7) Humidity + + + Redistribute condition IDs + + diff --git a/src/mapview.cpp b/src/mapview.cpp index 11fe039..600d5c1 100644 --- a/src/mapview.cpp +++ b/src/mapview.cpp @@ -410,7 +410,7 @@ void MapView::showContextMenu(const QPoint &pos) int wmax = 0; for (auto& it : cpy_dat) { - int w = menu.fontMetrics().horizontalAdvance(it.txt + " "); + int w = txtWidth(menu.fontMetrics(), it.txt + " "); if (w > wmax) wmax = w; } @@ -419,7 +419,7 @@ void MapView::showContextMenu(const QPoint &pos) if (world) { QString txt = tr("Copy seed:"); - while (menu.fontMetrics().horizontalAdvance(txt + " ") < wmax) + while (txtWidth(menu.fontMetrics(), txt + " ") < wmax) txt += " "; txt += QString::asprintf("%" PRId64, (int64_t)world->wi.seed); menu.addAction(txt, this, &MapView::copySeed, QKeySequence::Copy); @@ -427,7 +427,7 @@ void MapView::showContextMenu(const QPoint &pos) for (auto& it : cpy_dat) { QString txt = it.txt; - while (menu.fontMetrics().horizontalAdvance(txt + " ") < wmax) + while (txtWidth(menu.fontMetrics(), txt + " ") < wmax) txt += " "; txt += it.cpy; menu.addAction(txt, [=](){ this->copyText(it.cpy); }); diff --git a/src/presetdialog.cpp b/src/presetdialog.cpp index 91cb8e9..94baf91 100644 --- a/src/presetdialog.cpp +++ b/src/presetdialog.cpp @@ -57,7 +57,7 @@ PresetDialog::PresetDialog(QWidget *parent, WorldInfo wi, bool showEamples) , ui(new Ui::PresetDialog) { ui->setupUi(this); - resize(fontMetrics().horizontalAdvance('x') * 128, fontMetrics().height() * 32); + resize(txtWidth(fontMetrics()) * 128, fontMetrics().height() * 32); ui->labelMC->setText(tr("MC ") + mc2str(wi.mc)); connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); @@ -84,15 +84,6 @@ PresetDialog::PresetDialog(QWidget *parent, WorldInfo wi, bool showEamples) tr("An ideal Quad-hut next to a Stronghold with a Mushroom Island close by."), wi.mc >= MC_1_4); - /* - addPreset(":/examples/mushroom_icespike.txt", - tr("Analyze for location with rare biomes together (1.7+)"), - tr("Check a large area for a Mushroom Island that is next to Ice Spikes.\n\n" - "Use this in the Analysis Tab with the Condition trigger enabled to " - "find an instance in the current seed."), - wi.mc >= MC_1_7); - */ - addPreset(":/examples/two_zombie_villages.txt", tr("Abandoned Villages in separate biomes (1.10+)"), tr("Two abandoned Villages close together, one in a Plains, the other in a Desert.\n\n" @@ -135,20 +126,14 @@ PresetDialog::PresetDialog(QWidget *parent, WorldInfo wi, bool showEamples) "Looks for a suitable climate that primarily supports Jungle variants."), wi.mc >= MC_1_18); - addPreset(":/examples/large_birch_forest_1_18.txt", - tr("Large Birch Forest (1.18+)"), - tr("A large Birch Forest biome at the origin.\n\n" - "Looks for a climate that supports Birch Forest variants. " - "Swamps and Meadows can generate in the same climates and are " - "explicitly excluded."), - wi.mc >= MC_1_18); - + /* addPreset(":/examples/old_growth_taiga_somewhere.txt", tr("Large Old Growth Taiga somewhere (1.18+)"), tr("A large Old Growth Taiga biome somewhere within 2500 blocks.\n\n" "Searches an area of +/-2500 blocks for a large climate region that " "primarily supports Old Growth Taiga variants"), wi.mc >= MC_1_18); + */ } PresetDialog::~PresetDialog() diff --git a/src/search.cpp b/src/search.cpp index 130372b..0a97011 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -56,6 +56,10 @@ QString Condition::summary(bool aligntab) const else txts += ": " + QApplication::translate("Filter", "[script missing]"); } + else if (step) + { + txts += QString(" 1:%1").arg(step); + } } if (aligntab) @@ -127,22 +131,37 @@ bool Condition::versionUpgrade() if (version < VER_4_0_0) { const FilterInfo& ft = g_filterinfo.list[type]; - if (ft.grid > 1) + switch (type) { - x1 = x1 * ft.grid; - z1 = z1 * ft.grid; - x2 = (x2+1) * ft.grid - 1; - z2 = (z2+1) * ft.grid - 1; + case F_SPIRAL: step = 1; break; + case F_SPIRAL_4: step = 4; type = F_SPIRAL; break; + case F_SPIRAL_16: step = 16; type = F_SPIRAL; break; + case F_SPIRAL_64: step = 64; type = F_SPIRAL; break; + case F_SPIRAL_256: step = 256; type = F_SPIRAL; break; + case F_SPIRAL_512: step = 512; type = F_SPIRAL; break; + case F_SPIRAL_1024: step = 1024; type = F_SPIRAL; break; + case F_BIOME: step = 1; break; + case F_BIOME_4: step = 4; type = F_BIOME; break; + case F_BIOME_16: step = 16; type = F_BIOME; break; + case F_BIOME_64: step = 64; type = F_BIOME; break; + case F_BIOME_256: step = 256; type = F_BIOME; break; + case F_BIOME_NETHER: step = 1; break; + case F_BIOME_NETHER_4: step = 4; type = F_BIOME_NETHER; break; + case F_BIOME_NETHER_16: step = 16; type = F_BIOME_NETHER; break; + case F_BIOME_NETHER_64: step = 64; type = F_BIOME_NETHER; break; + case F_BIOME_NETHER_256:step = 256; type = F_BIOME_NETHER; break; + case F_BIOME_END: step = 1; break; + case F_BIOME_END_4: step = 4; type = F_BIOME_END; break; + case F_BIOME_END_16: step = 16; type = F_BIOME_END; break; + case F_BIOME_END_64: step = 64; type = F_BIOME_END; break; } - switch (type) + int mult = step ? step : ft.grid; + if (mult > 1) { - case F_SPIRAL: step = 1; break; - case F_SPIRAL_4: step = 4; type = F_SPIRAL; break; - case F_SPIRAL_16: step = 16; type = F_SPIRAL; break; - case F_SPIRAL_64: step = 64; type = F_SPIRAL; break; - case F_SPIRAL_256: step = 256; type = F_SPIRAL; break; - case F_SPIRAL_512: step = 512; type = F_SPIRAL; break; - case F_SPIRAL_1024: step = 1024; type = F_SPIRAL; break; + x1 = x1 * mult; + z1 = z1 * mult; + x2 = (x2+1) * mult - 1; + z2 = (z2+1) * mult - 1; } } @@ -398,7 +417,7 @@ int testTreeAt( if (inr) { - // children are combined via AND + // children are combined via AND at the current position int sta = COND_OK; for (int b : branches) { @@ -462,7 +481,7 @@ int testTreeAt( return st; - case F_LOGIC_OR: //qDebug() << at.x << at.z; return COND_FAILED; + case F_LOGIC_OR: if (branches.empty()) { if (path) @@ -500,7 +519,9 @@ int testTreeAt( return st; - case F_LOGIC_NOT: + case F_LOGIC_NOT: //qDebug() << at.x << at.z; + if (branches.empty()) + return COND_FAILED; st = COND_OK; for (int b : branches) { @@ -967,8 +988,8 @@ static int f_biome_sampler(Generator *g, int scale, int x, int y, int z, void *d return -2; if (info->rmaxsq) { - int dx = x - info->at.x; - int dz = z - info->at.z; + int dx = (x * scale) - info->at.x; + int dz = (z * scale) - info->at.z; int64_t rsq = dx*(int64_t)dx + dz*(int64_t)dz; if (rsq >= info->rmaxsq) return -1; @@ -985,6 +1006,8 @@ static int f_biome_sampler(Generator *g, int scale, int x, int y, int z, void *d } if (incl != 0) { + x *= scale; + z *= scale; if (info->imax && info->n < MAX_INSTANCES) info->cent[info->n] = Pos{x, z}; info->xsum += x; @@ -1036,6 +1059,7 @@ testCondAt( if (!getStructureConfig_override(finfo.stype, env->mc, &sconf)) return COND_FAILED; } + else memset(&sconf, 0, sizeof(sconf)); // never relevant, but clang-analyzer complains if (cond->rmax > 0) { @@ -1725,7 +1749,8 @@ testCondAt( return COND_FAILED; if (cond->converage <= 0 || cond->converage > 1) return COND_FAILED; - s = finfo.pow2; + + s = 2; rx1 = x1 >> s; rz1 = z1 >> s; rx2 = x2 >> s; @@ -1738,6 +1763,7 @@ testCondAt( sample_boime_t sample; sample.cond = cond; sample.at = at; + sample.rmaxsq = rmax; sample.n = 0; sample.xsum = 0; sample.zsum = 0; @@ -1770,18 +1796,14 @@ testCondAt( } return COND_FAILED; - // biome filters reference specific layers - // MAYBE: options for layers in different versions? - case F_BIOME: - if (env->mc <= MC_B1_7 || env->mc >= MC_1_18) - goto L_noise_biome; - // fallthrough + case F_BIOME_4_RIVER: case F_BIOME_256_OTEMP: if (env->mc >= MC_1_18) return COND_FAILED; - s = finfo.pow2; + + s = cond->type == F_BIOME_4_RIVER ? 2 : 8; rx1 = x1 >> s; rz1 = z1 >> s; rx2 = x2 >> s; @@ -1793,7 +1815,7 @@ testCondAt( return COND_MAYBE_POS_VALID; if (pass == PASS_FULL_48) { - if (env->mc < MC_1_13 || finfo.layer != L_OCEAN_TEMP_256) + if (env->mc < MC_1_13 || cond->type != F_BIOME_256_OTEMP) return COND_MAYBE_POS_VALID; } valid = COND_FAILED; @@ -1802,7 +1824,12 @@ testCondAt( int w = rx2-rx1+1; int h = rz2-rz1+1; //env->init4Dim(0); // seed gets applied by checkForBiomesAtLayer - if (checkForBiomesAtLayer(&env->g.ls, &env->g.ls.layers[finfo.layer], + Layer *entry; + if (cond->type == F_BIOME_4_RIVER) + entry = &env->g.ls.layers[L_RIVER_4]; + else + entry = &env->g.ls.layers[L_OCEAN_TEMP_256]; + if (checkForBiomesAtLayer(&env->g.ls, entry, NULL, env->seed, rx1, rz1, w, h, &cond->bf) > 0) { valid = COND_OK; @@ -1829,21 +1856,20 @@ testCondAt( return COND_FAILED; - case F_BIOME_4: - case F_BIOME_16: - case F_BIOME_64: - case F_BIOME_256: - case F_BIOME_NETHER_1: - case F_BIOME_NETHER_4: - case F_BIOME_NETHER_16: - case F_BIOME_NETHER_64: - case F_BIOME_END_1: - case F_BIOME_END_4: - case F_BIOME_END_16: - case F_BIOME_END_64: - -L_noise_biome: - s = finfo.pow2; + case F_BIOME: + case F_BIOME_NETHER: + case F_BIOME_END: + + switch (cond->step) + { + case 1: s = 0; break; + case 4: s = 2; break; + case 16: s = 4; break; + case 64: s = 6; break; + case 256: s = 8; break; + default: return COND_FAILED; + } + rx1 = x1 >> s; rz1 = z1 >> s; rx2 = x2 >> s; @@ -1855,8 +1881,9 @@ testCondAt( return COND_MAYBE_POS_VALID; // the Nether and End require only the 48-bit seed // (except voronoi uses the full 64-bits) - if (pass == PASS_FULL_48 && finfo.dep64) + if (pass != PASS_FULL_64 && (finfo.dep64 || s == 0)) return COND_MAYBE_POS_VALID; + else { int w = rx2 - rx1 + 1; int h = rz2 - rz1 + 1; @@ -1872,7 +1899,7 @@ testCondAt( case F_BIOME_CENTER_256: if (pass == PASS_FULL_64) { - s = finfo.pow2; + s = cond->type == F_BIOME_CENTER ? 2 : 8; rx1 = x1 >> s; rz1 = z1 >> s; rx2 = x2 >> s; @@ -1882,7 +1909,7 @@ testCondAt( Range r = {1<y >> 2, 1}; env->init4Dim(DIM_OVERWORLD); - if (cond->count == 0) + if (cond->count <= 0) { // exclusion icnt = getBiomeCenters( cent, NULL, 1, &env->g, r, cond->biomeId, cond->biomeSize, cond->tol, @@ -1963,15 +1990,20 @@ testCondAt( double *p_max = (cond->minmax & Condition::E_LOCATE_MAX) ? para+1 : nullptr; getParaRange(&env->g.bn.climate[cond->para], p_min, p_max, rx1, rz1, w, h, &info, f_track_minmax); - double v; double vmin = cond->minmax & Condition::E_TEST_LOWER ? cond->vmin : -INFINITY; double vmax = cond->minmax & Condition::E_TEST_UPPER ? cond->vmax : +INFINITY; - v = p_min ? info.vmin : info.vmax; - if (v < vmin) - return COND_FAILED; - v = p_max ? info.vmax : info.vmin; - if (v > vmax) - return COND_FAILED; + double evalmin = p_min ? info.vmin : info.vmax; + double evalmax = p_max ? info.vmax : info.vmin; + if (cond->flags & Condition::FLG_INVERT) + { + if (evalmin > vmin && evalmax < vmax) + return COND_FAILED; + } + else + { + if (evalmin < vmin || evalmax > vmax) + return COND_FAILED; + } *cent = at; if (imax) *imax = 1; if (cond->minmax & Condition::E_LOCATE_MIN) diff --git a/src/search.h b/src/search.h index f527290..83f916f 100644 --- a/src/search.h +++ b/src/search.h @@ -17,8 +17,6 @@ enum CAT_QUAD, CAT_STRUCT, CAT_BIOMES, - CAT_NETHER, - CAT_END, CAT_OTHER, CATEGORY_MAX, }; @@ -57,12 +55,12 @@ enum F_FORTRESS, F_BASTION, F_ENDCITY, - F_BIOME_NETHER_1, + F_BIOME_NETHER, F_BIOME_NETHER_4, F_BIOME_NETHER_16, F_BIOME_NETHER_64, F_BIOME_NETHER_256, - F_BIOME_END_1, + F_BIOME_END, F_BIOME_END_4, F_BIOME_END_16, F_BIOME_END_64, @@ -115,10 +113,8 @@ struct FilterInfo int cat; // seed source category bool dep64; // depends on 64-bit seed int loc; - int layer; // associated generator layer int stype; // structure type int grid; // coordinate multiplier - int pow2; // bit position of grid int branch; // branching behaviour int mcmin; // minimum version int mcmax; // maximum version @@ -140,13 +136,13 @@ static const struct FilterList : private FilterInfo int disp = 0; // display order list[F_SELECT] = FilterInfo{ - CAT_NONE, 0, LOC_NIL, 0, 0, 0, 0, BR_NONE, MC_UNDEF, MC_NEWEST, 0, 0, disp++, + CAT_NONE, 0, LOC_NIL, 0, 0, BR_NONE, MC_UNDEF, MC_NEWEST, 0, 0, disp++, NULL, "", "" }; list[F_LOGIC_OR] = FilterInfo{ - CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, + CAT_HELPER, 0, LOC_NIL, 0, 1, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, "helper", QT_TRANSLATE_NOOP("Filter", "OR logic gate"), QT_TRANSLATE_NOOP("Filter", @@ -155,7 +151,7 @@ static const struct FilterList : private FilterInfo "defined, it defaults to true.") }; list[F_LOGIC_NOT] = FilterInfo{ - CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, + CAT_HELPER, 0, LOC_NIL, 0, 1, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, "helper", QT_TRANSLATE_NOOP("Filter", "NOT logic gate"), QT_TRANSLATE_NOOP("Filter", @@ -164,28 +160,28 @@ static const struct FilterList : private FilterInfo "defined, it defaults to true.") }; list[F_LUA] = FilterInfo{ - CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, + CAT_HELPER, 0, LOC_NIL, 0, 1, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, "helper", QT_TRANSLATE_NOOP("Filter", "Lua"), QT_TRANSLATE_NOOP("Filter", "Define custom conditions using Lua scripts.") }; list[F_SCALE_TO_NETHER] = FilterInfo{ - CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, + CAT_HELPER, 0, LOC_NIL, 0, 1, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, "portal_lit", QT_TRANSLATE_NOOP("Filter", "Coordinate factor x/8"), QT_TRANSLATE_NOOP("Filter", "Divides relative location by 8, from Overworld to Nether.") }; list[F_SCALE_TO_OVERWORLD] = FilterInfo{ - CAT_HELPER, 0, LOC_NIL, 0, 0, 1, 0, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, + CAT_HELPER, 0, LOC_NIL, 0, 1, BR_NONE, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, "portal_lit", QT_TRANSLATE_NOOP("Filter", "Coordinate factor x*8"), QT_TRANSLATE_NOOP("Filter", "Multiplies relative location by 8, from Nether to Overworld.") }; list[F_SPIRAL] = FilterInfo{ - CAT_HELPER, 0, LOC_RAD, 0, 0, 1, 0, BR_FIRST, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, + CAT_HELPER, 0, LOC_RAD, 0, 1, BR_FIRST, MC_UNDEF, MC_NEWEST, DIM_UNDEF, 0, disp++, "reference", QT_TRANSLATE_NOOP("Filter", "Spiral iterator"), QT_TRANSLATE_NOOP("Filter", @@ -198,7 +194,7 @@ static const struct FilterList : private FilterInfo }; list[F_QH_IDEAL] = FilterInfo{ - CAT_QUAD, 0, LOC_RAD, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, + CAT_QUAD, 0, LOC_RAD, Swamp_Hut, 512, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, "quad", QT_TRANSLATE_NOOP("Filter", "Quad-hut (ideal)"), QT_TRANSLATE_NOOP("Filter", @@ -207,7 +203,7 @@ static const struct FilterList : private FilterInfo }; list[F_QH_CLASSIC] = FilterInfo{ - CAT_QUAD, 0, LOC_RAD, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, + CAT_QUAD, 0, LOC_RAD, Swamp_Hut, 512, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, "quad", QT_TRANSLATE_NOOP("Filter", "Quad-hut (classic)"), QT_TRANSLATE_NOOP("Filter", @@ -218,7 +214,7 @@ static const struct FilterList : private FilterInfo }; list[F_QH_NORMAL] = FilterInfo{ - CAT_QUAD, 0, LOC_RAD, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, + CAT_QUAD, 0, LOC_RAD, Swamp_Hut, 512, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, "quad", QT_TRANSLATE_NOOP("Filter", "Quad-hut (normal)"), QT_TRANSLATE_NOOP("Filter", @@ -229,7 +225,7 @@ static const struct FilterList : private FilterInfo }; list[F_QH_BARELY] = FilterInfo{ - CAT_QUAD, 0, LOC_RAD, 0, Swamp_Hut, 512, 9, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, + CAT_QUAD, 0, LOC_RAD, Swamp_Hut, 512, BR_FIRST, MC_1_4, MC_NEWEST, 0, 0, disp++, "quad", QT_TRANSLATE_NOOP("Filter", "Quad-hut (barely)"), QT_TRANSLATE_NOOP("Filter", @@ -239,7 +235,7 @@ static const struct FilterList : private FilterInfo }; list[F_QM_95] = FilterInfo{ - CAT_QUAD, 0, LOC_RAD, 0, Monument, 512, 9, BR_FIRST, MC_1_8, MC_NEWEST, 0, 0, disp++, + CAT_QUAD, 0, LOC_RAD, Monument, 512, BR_FIRST, MC_1_8, MC_NEWEST, 0, 0, disp++, "quad", QT_TRANSLATE_NOOP("Filter", "Quad-ocean-monument (>95%)"), QT_TRANSLATE_NOOP("Filter", @@ -249,7 +245,7 @@ static const struct FilterList : private FilterInfo }; list[F_QM_90] = FilterInfo{ - CAT_QUAD, 0, LOC_RAD, 0, Monument, 512, 9, BR_FIRST, MC_1_8, MC_NEWEST, 0, 0, disp++, + CAT_QUAD, 0, LOC_RAD, Monument, 512, BR_FIRST, MC_1_8, MC_NEWEST, 0, 0, disp++, "quad", QT_TRANSLATE_NOOP("Filter", "Quad-ocean-monument (>90%)"), QT_TRANSLATE_NOOP("Filter", @@ -259,8 +255,8 @@ static const struct FilterList : private FilterInfo }; list[F_BIOME_SAMPLE] = FilterInfo{ - CAT_BIOMES, 1, LOC_RAD, 0, 0, 1, 0, BR_SPLIT, MC_B1_7, MC_NEWEST, 0, 1, disp++, - "map", + CAT_BIOMES, 1, LOC_RAD, 0, 1, BR_SPLIT, MC_B1_7, MC_NEWEST, 0, 1, disp++, + "overworld", QT_TRANSLATE_NOOP("Filter", "Biome samples"), QT_TRANSLATE_NOOP("Filter", "Samples biomes in a given area to find if a proportion of the " @@ -268,51 +264,32 @@ static const struct FilterList : private FilterInfo }; list[F_BIOME] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, L_VORONOI_1, 0, 1, 0, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++, - "map", - QT_TRANSLATE_NOOP("Filter", "Biome scaled"), - QT_TRANSLATE_NOOP("Filter", - "Allows only seeds with the included (+) biomes in the specified area and " - "discard those that have biomes that are explicitly excluded (-).") - }; - - list[F_BIOME_4] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++, - "map", - QT_TRANSLATE_NOOP("Filter", "Biomes 1:4"), + CAT_BIOMES, 1, LOC_REC, 0, 1, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++, + "overworld", + QT_TRANSLATE_NOOP("Filter", "Overworld at scale"), QT_TRANSLATE_NOOP("Filter", "Allows only seeds with the included (+) biomes in the specified area and " "discard those that have biomes that are explicitly excluded (-).") }; - list[F_BIOME_16] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, 0, 0, 16, 4, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++, - "map", - QT_TRANSLATE_NOOP("Filter", "Biomes 1:16"), - QT_TRANSLATE_NOOP("Filter", - "Allows only seeds with the included (+) biomes in the specified area and " - "discard those that have biomes that are explicitly excluded (-).") - }; - list[F_BIOME_64] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, 0, 0, 64, 6, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++, - "map", - QT_TRANSLATE_NOOP("Filter", "Biomes 1:64"), + list[F_BIOME_NETHER] = FilterInfo{ + CAT_BIOMES, 0, LOC_REC, 0, 1, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 1, disp++, + "nether", + QT_TRANSLATE_NOOP("Filter", "Nether at scale"), QT_TRANSLATE_NOOP("Filter", - "Allows only seeds with the included (+) biomes in the specified area and " - "discard those that have biomes that are explicitly excluded (-).") + "Nether biomes sampled on a scaled grid.") }; - list[F_BIOME_256] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, 0, 0, 256, 8, BR_NONE, MC_B1_7, MC_NEWEST, 0, 1, disp++, - "map", - QT_TRANSLATE_NOOP("Filter", "Biomes 1:256"), + list[F_BIOME_END] = FilterInfo{ + CAT_BIOMES, 0, LOC_REC, 0, 1, BR_NONE, MC_1_9, MC_NEWEST, +1, 1, disp++, + "the_end", + QT_TRANSLATE_NOOP("Filter", "End at scale"), QT_TRANSLATE_NOOP("Filter", - "Allows only seeds with the included (+) biomes in the specified area and " - "discard those that have biomes that are explicitly excluded (-).") + "End biomes sampled on a scaled grid.") }; list[F_BIOME_4_RIVER] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, L_RIVER_MIX_4, 0, 4, 2, BR_NONE, MC_1_13, MC_1_17, 0, 0, disp++, + CAT_BIOMES, 1, LOC_REC, 0, 4, BR_NONE, MC_1_13, MC_1_17, 0, 0, disp++, "map", - QT_TRANSLATE_NOOP("Filter", "Biomes 1:4 RIVER"), + QT_TRANSLATE_NOOP("Filter", "Biome layer 1:4 RIVER"), QT_TRANSLATE_NOOP("Filter", "Allows only seeds with the included (+) biomes in the specified area and " "discard those that have biomes that are explicitly excluded (-) " @@ -320,132 +297,68 @@ static const struct FilterList : private FilterInfo "This layer does not generate ocean variants.") }; list[F_BIOME_256_OTEMP] = FilterInfo{ - CAT_BIOMES, 0, LOC_REC, L_OCEAN_TEMP_256, 0, 256, 8, BR_NONE, MC_1_13, MC_1_17, 0, 0, disp++, + CAT_BIOMES, 0, LOC_REC, 0, 256, BR_NONE, MC_1_13, MC_1_17, 0, 0, disp++, "map", - QT_TRANSLATE_NOOP("Filter", "Biomes 1:256 O.TEMP"), + QT_TRANSLATE_NOOP("Filter", "Biome layer 1:256 O.TEMP"), QT_TRANSLATE_NOOP("Filter", "Allows only seeds with the included (+) biomes in the specified area and " "discard those that have biomes that are explicitly excluded (-) " "at layer OCEAN TEMPERATURE with scale 1:256. " "This generation layer depends only on the lower 48-bits of the seed.") }; + list[F_CLIMATE_NOISE] = FilterInfo{ - CAT_BIOMES, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_18, MC_NEWEST, 0, 0, disp++, - "map", - QT_TRANSLATE_NOOP("Filter", "Climate parameters 1:4"), + CAT_BIOMES, 0, LOC_REC, 0, 4, BR_NONE, MC_1_18, MC_NEWEST, 0, 0, disp++, + "overworld", + QT_TRANSLATE_NOOP("Filter", "Climate parameters"), QT_TRANSLATE_NOOP("Filter", "Custom limits for the required and allowed climate noise parameters that " "the specified area should cover.") }; list[F_CLIMATE_MINMAX] = FilterInfo{ - CAT_BIOMES, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_18, MC_NEWEST, 0, 0, disp++, - "map", - QT_TRANSLATE_NOOP("Filter", "Locate climate extreme 1:4"), + CAT_BIOMES, 0, LOC_REC, 0, 4, BR_NONE, MC_1_18, MC_NEWEST, 0, 0, disp++, + "overworld", + QT_TRANSLATE_NOOP("Filter", "Locate climate extreme"), QT_TRANSLATE_NOOP("Filter", "Finds the location where a climate parameter reaches its minimum or maximum.") }; list[F_BIOME_CENTER] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, 0, 0, 4, 2, BR_CLUST, MC_B1_7, MC_NEWEST, 0, 1, disp++, + CAT_BIOMES, 1, LOC_REC, 0, 4, BR_CLUST, MC_B1_7, MC_NEWEST, 0, 1, disp++, "map", - QT_TRANSLATE_NOOP("Filter", "Locate biome center 1:4"), + QT_TRANSLATE_NOOP("Filter", "Locate biome center"), QT_TRANSLATE_NOOP("Filter", "Finds the center position of a given biome.") }; list[F_BIOME_CENTER_256] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, 0, 0, 256, 8, BR_CLUST, MC_B1_7, MC_1_17, 0, 1, disp++, + CAT_BIOMES, 1, LOC_REC, 0, 256, BR_CLUST, MC_B1_7, MC_1_17, 0, 1, disp++, "map", QT_TRANSLATE_NOOP("Filter", "Locate biome center 1:256"), QT_TRANSLATE_NOOP("Filter", "Finds the center position of a given biome. Based on the 1:256 biome layer.") }; list[F_TEMPS] = FilterInfo{ - CAT_BIOMES, 1, LOC_REC, 0, 0, 1024, 10, BR_NONE, MC_1_7, MC_1_17, 0, 0, disp++, + CAT_BIOMES, 1, LOC_REC, 0, 1024, BR_NONE, MC_1_7, MC_1_17, 0, 0, disp++, "tempcat", QT_TRANSLATE_NOOP("Filter", "Temperature categories"), QT_TRANSLATE_NOOP("Filter", "Checks that the area has a minimum of all the required temperature categories.") }; - list[F_BIOME_NETHER_1] = FilterInfo{ - CAT_NETHER, 1, LOC_REC, 0, 0, 1, 0, BR_NONE, MC_1_16_1, 0, -1, 1, disp++, // disabled - "nether", - QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:1 (disabled)"), - QT_TRANSLATE_NOOP("Filter", - "Nether biomes after voronoi scaling to 1:1.") - }; - list[F_BIOME_NETHER_4] = FilterInfo{ - CAT_NETHER, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++, - "nether", - QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:4"), - QT_TRANSLATE_NOOP("Filter", - "Nether biomes with normal noise sampling at scale 1:4.") - }; - list[F_BIOME_NETHER_16] = FilterInfo{ - CAT_NETHER, 0, LOC_REC, 0, 0, 16, 4, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++, - "nether", - QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:16"), - QT_TRANSLATE_NOOP("Filter", - "Nether biomes, but only sampled at scale 1:16.") - }; - list[F_BIOME_NETHER_64] = FilterInfo{ - CAT_NETHER, 0, LOC_REC, 0, 0, 64, 6, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++, - "nether", - QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:64"), - QT_TRANSLATE_NOOP("Filter", - "Nether biomes, but only sampled at scale 1:64.") - }; - list[F_BIOME_NETHER_256] = FilterInfo{ - CAT_NETHER, 0, LOC_REC, 0, 0, 256, 8, BR_NONE, MC_1_16_1, MC_NEWEST, -1, 0, disp++, - "nether", - QT_TRANSLATE_NOOP("Filter", "Nether biomes 1:256"), - QT_TRANSLATE_NOOP("Filter", - "Nether biomes, but only sampled at scale 1:256.") - }; - - list[F_BIOME_END_1] = FilterInfo{ - CAT_END, 1, LOC_REC, 0, 0, 1, 0, BR_NONE, MC_1_9, 0, +1, 1, disp++, // disabled - "the_end", - QT_TRANSLATE_NOOP("Filter", "End biomes 1:1 (disabled)"), - QT_TRANSLATE_NOOP("Filter", - "End biomes after voronoi scaling to 1:1.") - }; - list[F_BIOME_END_4] = FilterInfo{ - CAT_END, 0, LOC_REC, 0, 0, 4, 2, BR_NONE, MC_1_9, MC_NEWEST, +1, 0, disp++, - "the_end", - QT_TRANSLATE_NOOP("Filter", "End biomes 1:4"), - QT_TRANSLATE_NOOP("Filter", - "End biomes sampled at scale 1:4. Note this is just a simple upscale of 1:16.") - }; - list[F_BIOME_END_16] = FilterInfo{ - CAT_END, 0, LOC_REC, 0, 0, 16, 4, BR_NONE, MC_1_9, MC_NEWEST, +1, 0, disp++, - "the_end", - QT_TRANSLATE_NOOP("Filter", "End biomes 1:16"), - QT_TRANSLATE_NOOP("Filter", - "End biomes with normal sampling at scale 1:16.") - }; - list[F_BIOME_END_64] = FilterInfo{ - CAT_END, 0, LOC_REC, 0, 0, 64, 6, BR_NONE, MC_1_9, MC_NEWEST, +1, 0, disp++, - "the_end", - QT_TRANSLATE_NOOP("Filter", "End biomes 1:64"), - QT_TRANSLATE_NOOP("Filter", - "End biomes with lossy sampling at scale 1:64.") - }; - list[F_SPAWN] = FilterInfo{ - CAT_OTHER, 1, LOC_RAD, 0, 0, 1, 0, BR_NONE, MC_B1_8, MC_NEWEST, 0, 0, disp++, + CAT_OTHER, 1, LOC_RAD, 0, 1, BR_NONE, MC_B1_8, MC_NEWEST, 0, 0, disp++, "spawn", QT_TRANSLATE_NOOP("Filter", "Spawn"), "" }; list[F_SLIME] = FilterInfo{ - CAT_OTHER, 0, LOC_REC, 0, 0, 16, 4, BR_CLUST, MC_UNDEF, MC_NEWEST, 0, 0, disp++, + CAT_OTHER, 0, LOC_REC, 0, 16, BR_CLUST, MC_UNDEF, MC_NEWEST, 0, 0, disp++, "slime", QT_TRANSLATE_NOOP("Filter", "Slime chunk"), "" }; list[F_HEIGHT] = FilterInfo{ - CAT_OTHER, 0, LOC_POS, 0, 0, 4, 2, BR_NONE, MC_1_1, MC_NEWEST, 0, 0, disp++, + CAT_OTHER, 0, LOC_POS, 0, 4, BR_NONE, MC_1_1, MC_NEWEST, 0, 0, disp++, "height", QT_TRANSLATE_NOOP("Filter", "Surface height"), QT_TRANSLATE_NOOP("Filter", @@ -453,7 +366,7 @@ static const struct FilterList : private FilterInfo }; list[F_FIRST_STRONGHOLD] = FilterInfo{ - CAT_OTHER, 0, LOC_RAD, 0, 0, 1, 0, BR_NONE, MC_B1_8, MC_NEWEST, 0, 0, disp++, + CAT_OTHER, 0, LOC_RAD, 0, 1, BR_NONE, MC_B1_8, MC_NEWEST, 0, 0, disp++, "stronghold", QT_TRANSLATE_NOOP("Filter", "First stronghold"), QT_TRANSLATE_NOOP("Filter", @@ -462,28 +375,28 @@ static const struct FilterList : private FilterInfo }; list[F_STRONGHOLD] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, 0, 1, 0, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, 0, 1, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++, "stronghold", QT_TRANSLATE_NOOP("Filter", "Stronghold"), "" }; list[F_VILLAGE] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Village, 1, 0, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Village, 1, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++, "village", QT_TRANSLATE_NOOP("Filter", "Village"), "" }; list[F_MINESHAFT] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Mineshaft, 1, 0, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Mineshaft, 1, BR_CLUST, MC_B1_8, MC_NEWEST, 0, 0, disp++, "mineshaft", QT_TRANSLATE_NOOP("Filter", "Abandoned mineshaft"), "" }; list[F_DESERT] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Desert_Pyramid, 1, 0, BR_CLUST, MC_1_3, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Desert_Pyramid, 1, BR_CLUST, MC_1_3, MC_NEWEST, 0, 0, disp++, "desert", QT_TRANSLATE_NOOP("Filter", "Desert pyramid"), QT_TRANSLATE_NOOP("Filter", @@ -492,7 +405,7 @@ static const struct FilterList : private FilterInfo }; list[F_JUNGLE] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Jungle_Temple, 1, 0, BR_CLUST, MC_1_3, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Jungle_Temple, 1, BR_CLUST, MC_1_3, MC_NEWEST, 0, 0, disp++, "jungle", QT_TRANSLATE_NOOP("Filter", "Jungle temple"), QT_TRANSLATE_NOOP("Filter", @@ -501,28 +414,28 @@ static const struct FilterList : private FilterInfo }; list[F_HUT] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Swamp_Hut, 1, 0, BR_CLUST, MC_1_4, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Swamp_Hut, 1, BR_CLUST, MC_1_4, MC_NEWEST, 0, 0, disp++, "hut", QT_TRANSLATE_NOOP("Filter", "Swamp hut"), "" }; list[F_MONUMENT] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Monument, 1, 0, BR_CLUST, MC_1_8, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Monument, 1, BR_CLUST, MC_1_8, MC_NEWEST, 0, 0, disp++, "monument", QT_TRANSLATE_NOOP("Filter", "Ocean monument"), "" }; list[F_IGLOO] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Igloo, 1, 0, BR_CLUST, MC_1_9, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Igloo, 1, BR_CLUST, MC_1_9, MC_NEWEST, 0, 0, disp++, "igloo", QT_TRANSLATE_NOOP("Filter", "Igloo"), "" }; list[F_MANSION] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Mansion, 1, 0, BR_CLUST, MC_1_11, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Mansion, 1, BR_CLUST, MC_1_11, MC_NEWEST, 0, 0, disp++, "mansion", QT_TRANSLATE_NOOP("Filter", "Woodland mansion"), QT_TRANSLATE_NOOP("Filter", @@ -531,21 +444,21 @@ static const struct FilterList : private FilterInfo }; list[F_RUINS] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Ocean_Ruin, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Ocean_Ruin, 1, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, "ruins", QT_TRANSLATE_NOOP("Filter", "Ocean ruins"), "" }; list[F_SHIPWRECK] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Shipwreck, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Shipwreck, 1, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, "shipwreck", QT_TRANSLATE_NOOP("Filter", "Shipwreck"), "" }; list[F_TREASURE] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Treasure, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Treasure, 1, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, "treasure", QT_TRANSLATE_NOOP("Filter", "Buried treasure"), QT_TRANSLATE_NOOP("Filter", @@ -555,70 +468,70 @@ static const struct FilterList : private FilterInfo }; list[F_WELL] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Desert_Well, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Desert_Well, 1, BR_CLUST, MC_1_13, MC_NEWEST, 0, 0, disp++, "well", QT_TRANSLATE_NOOP("Filter", "Desert well"), "" }; list[F_OUTPOST] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Outpost, 1, 0, BR_CLUST, MC_1_14, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Outpost, 1, BR_CLUST, MC_1_14, MC_NEWEST, 0, 0, disp++, "outpost", QT_TRANSLATE_NOOP("Filter", "Pillager outpost"), "" }; list[F_ANCIENT_CITY] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Ancient_City, 1, 0, BR_CLUST, MC_1_19, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Ancient_City, 1, BR_CLUST, MC_1_19, MC_NEWEST, 0, 0, disp++, "ancient_city", QT_TRANSLATE_NOOP("Filter", "Ancient city"), "" }; list[F_TRAILS] = FilterInfo{ - CAT_STRUCT, 1, LOC_RAD, 0, Trail_Ruin, 1, 0, BR_CLUST, MC_1_20, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 1, LOC_RAD, Trail_Ruin, 1, BR_CLUST, MC_1_20, MC_NEWEST, 0, 0, disp++, "trails", QT_TRANSLATE_NOOP("Filter", "Trail ruins"), "" }; list[F_PORTAL] = FilterInfo{ - CAT_STRUCT, 0, LOC_RAD, 0, Ruined_Portal, 1, 0, BR_CLUST, MC_1_16_1, MC_NEWEST, 0, 0, disp++, + CAT_STRUCT, 0, LOC_RAD, Ruined_Portal, 1, BR_CLUST, MC_1_16_1, MC_NEWEST, 0, 0, disp++, "portal", QT_TRANSLATE_NOOP("Filter", "Ruined portal (overworld)"), "" }; list[F_PORTALN] = FilterInfo{ - CAT_STRUCT, 0, LOC_RAD, 0, Ruined_Portal_N, 1, 0, BR_CLUST, MC_1_16_1, MC_NEWEST, -1, 0, disp++, + CAT_STRUCT, 0, LOC_RAD, Ruined_Portal_N, 1, BR_CLUST, MC_1_16_1, MC_NEWEST, -1, 0, disp++, "portal", QT_TRANSLATE_NOOP("Filter", "Ruined portal (nether)"), "" }; list[F_FORTRESS] = FilterInfo{ - CAT_STRUCT, 0, LOC_RAD, 0, Fortress, 1, 0, BR_CLUST, MC_1_0, MC_NEWEST, -1, 0, disp++, + CAT_STRUCT, 0, LOC_RAD, Fortress, 1, BR_CLUST, MC_1_0, MC_NEWEST, -1, 0, disp++, "fortress", QT_TRANSLATE_NOOP("Filter", "Nether fortress"), "" }; list[F_BASTION] = FilterInfo{ - CAT_STRUCT, 0, LOC_RAD, 0, Bastion, 1, 0, BR_CLUST, MC_1_16_1, MC_NEWEST, -1, 0, disp++, + CAT_STRUCT, 0, LOC_RAD, Bastion, 1, BR_CLUST, MC_1_16_1, MC_NEWEST, -1, 0, disp++, "bastion", QT_TRANSLATE_NOOP("Filter", "Bastion remnant"), "" }; list[F_ENDCITY] = FilterInfo{ - CAT_STRUCT, 0, LOC_RAD, 0, End_City, 1, 0, BR_CLUST, MC_1_9, MC_NEWEST, +1, 0, disp++, + CAT_STRUCT, 0, LOC_RAD, End_City, 1, BR_CLUST, MC_1_9, MC_NEWEST, +1, 0, disp++, "endcity", QT_TRANSLATE_NOOP("Filter", "End city"), "" }; list[F_GATEWAY] = FilterInfo{ - CAT_STRUCT, 0, LOC_RAD, 0, End_Gateway, 1, 0, BR_CLUST, MC_1_13, MC_NEWEST, +1, 0, disp++, + CAT_STRUCT, 0, LOC_RAD, End_Gateway, 1, BR_CLUST, MC_1_13, MC_NEWEST, +1, 0, disp++, "gateway", QT_TRANSLATE_NOOP("Filter", "End gateway"), QT_TRANSLATE_NOOP("Filter", @@ -650,6 +563,7 @@ struct /*__attribute__((packed))*/ Condition FLG_APPROX = 0x0001, FLG_MATCH_ANY = 0x0010, FLG_IN_RANGE = 0x0020, + FLG_INVERT = 0x0040, }; enum { // variant flags VAR_WITH_START = 0x0001, // restrict start piece index and biome @@ -676,7 +590,7 @@ struct /*__attribute__((packed))*/ Condition char text[28]; uint8_t pad1[12]; // legacy uint64_t hash; - uint8_t deps[16]; // currently unused + int8_t deps[16]; // currently unused uint64_t biomeToFind, biomeToFindM; // inclusion biomes int32_t biomeId; // legacy oceanToFind(8) uint32_t biomeSize; diff --git a/src/searchthread.cpp b/src/searchthread.cpp index fc7449d..9f98308 100644 --- a/src/searchthread.cpp +++ b/src/searchthread.cpp @@ -234,13 +234,11 @@ bool SearchMaster::set(QWidget *widget, const Session& s) warn(widget, tr("Condition %1 not available for Minecraft versions above %2.").arg(cid, mcs)); return false; } - if (finfo.cat == CAT_BIOMES && - c.type != F_BIOME_CENTER && - c.type != F_BIOME_CENTER_256 && - c.type != F_TEMPS && - c.type != F_CLIMATE_NOISE && - c.type != F_CLIMATE_MINMAX) - { + if (c.type == F_BIOME || + c.type == F_BIOME_4_RIVER || + c.type == F_BIOME_256_OTEMP || + c.type == F_BIOME_SAMPLE + ){ uint64_t b = c.biomeToFind; uint64_t m = c.biomeToFindM; if ((c.biomeToExcl & b) || (c.biomeToExclM & m)) @@ -256,12 +254,23 @@ bool SearchMaster::set(QWidget *widget, const Session& s) return false; } - int layerId = finfo.layer; + int layerId = 0; + int scale = c.step; + if (c.type == F_BIOME_4_RIVER) + { + layerId = L_RIVER_4; + scale = 4; + } + else if (c.type == F_BIOME_256_OTEMP) + { + layerId = L_OCEAN_TEMP_256; + scale = 256; + } if (layerId == 0 && s.wi.mc <= MC_1_17) { Generator tmp; setupGenerator(&tmp, s.wi.mc, 0); - const Layer *l = getLayerForScale(&tmp, finfo.grid); + const Layer *l = getLayerForScale(&tmp, scale); if (l) layerId = l - tmp.ls.layers; } @@ -697,7 +706,7 @@ void SearchMaster::stop() for (SearchWorker *worker: workers) { long ms = stop_ms - timer.elapsed(); - if (mc < 1) ms = 1; + if (ms < 1) ms = 1; running += !worker->wait(ms); } if (!running) diff --git a/src/tabbiomes.cpp b/src/tabbiomes.cpp index 7c099ea..3df7bec 100644 --- a/src/tabbiomes.cpp +++ b/src/tabbiomes.cpp @@ -335,7 +335,7 @@ QSize BiomeHeader::sectionSizeFromContents(int section) const int margin = 2 * style()->pixelMetric(QStyle::PM_HeaderMargin, 0, this); QString s = model()->headerData(section, orientation()).toString(); QFontMetrics fm = fontMetrics(); - return QSize(fm.height() + 2*margin, fm.horizontalAdvance(s) + 2*margin); + return QSize(fm.height() + 2*margin, txtWidth(fm, s) + 2*margin); } @@ -409,10 +409,10 @@ bool TabBiomes::event(QEvent *e) if (e->type() == QEvent::LayoutRequest) { QFontMetrics fm = QFontMetrics(ui->treeLocate->font()); - ui->treeLocate->setColumnWidth(0, fm.horizontalAdvance('#') * 24); - ui->treeLocate->setColumnWidth(1, fm.horizontalAdvance('#') * 16); - ui->treeLocate->setColumnWidth(2, fm.horizontalAdvance('#') * 9); - ui->treeLocate->setColumnWidth(3, fm.horizontalAdvance('#') * 9); + ui->treeLocate->setColumnWidth(0, txtWidth(fm) * 24); + ui->treeLocate->setColumnWidth(1, txtWidth(fm) * 16); + ui->treeLocate->setColumnWidth(2, txtWidth(fm) * 9); + ui->treeLocate->setColumnWidth(3, txtWidth(fm) * 9); } return QWidget::event(e); } @@ -601,7 +601,7 @@ void TabBiomes::onBufferTimeout() continue; new_ids.insert(id); model->cnt[id][seed] = QVariant::fromValue(cnt); - int w = fm.horizontalAdvance(QString::number(cnt) + "#"); + int w = txtWidth(fm, QString::number(cnt) + "#"); if (w > colwidth[id]) colwidth[id] = w; } diff --git a/src/tablocations.cpp b/src/tablocations.cpp index 1129f7a..1bc04b6 100644 --- a/src/tablocations.cpp +++ b/src/tablocations.cpp @@ -154,11 +154,11 @@ bool TabLocations::event(QEvent *e) if (e->type() == QEvent::LayoutRequest) { QFontMetrics fm = QFontMetrics(ui->treeWidget->font()); - ui->treeWidget->setColumnWidth(0, fm.horizontalAdvance('#') * 9); - ui->treeWidget->setColumnWidth(1, fm.horizontalAdvance('#') * 36); - ui->treeWidget->setColumnWidth(2, fm.horizontalAdvance('#') * 9); - ui->treeWidget->setColumnWidth(3, fm.horizontalAdvance('#') * 9); - ui->treeWidget->setColumnWidth(4, fm.horizontalAdvance('#') * 9); + ui->treeWidget->setColumnWidth(0, txtWidth(fm) * 9); + ui->treeWidget->setColumnWidth(1, txtWidth(fm) * 36); + ui->treeWidget->setColumnWidth(2, txtWidth(fm) * 9); + ui->treeWidget->setColumnWidth(3, txtWidth(fm) * 9); + ui->treeWidget->setColumnWidth(4, txtWidth(fm) * 9); } return QWidget::event(e); } @@ -350,7 +350,7 @@ void TabLocations::on_pushStart_clicked() break; } } - qDebug() << thread.pos.size() << ":" << thread.pos.back().x << thread.pos.back().z << " t=" << t.elapsed(); + //qDebug() << thread.pos.size() << ":" << thread.pos.back().x << thread.pos.back().z << " t=" << t.elapsed(); } else if (mode == SMODE_SQUARE_SPIRAL) { @@ -451,7 +451,7 @@ void TabLocations::on_treeWidget_itemClicked(QTreeWidgetItem *item, int column) WorldInfo wi; parent->getSeed(&wi, false); - if (wi.seed != seed || dim != DIM_UNDEF) + if (wi.seed != seed || (dim != DIM_UNDEF && dim != parent->getDim())) { wi.seed = seed; parent->getMapView()->deleteWorld(); @@ -493,7 +493,7 @@ void csvline(QTextStream& stream, const QString& qte, const QString& sep, QStrin void TabLocations::on_pushExport_clicked() { QString fnam = QFileDialog::getSaveFileName( - this, tr("Export trigger analysis"), parent->prevdir, tr("Text files (*.txt *csv);;Any files (*)")); + this, tr("Export locations"), parent->prevdir, tr("Text files (*.txt *csv);;Any files (*)")); if (fnam.isEmpty()) return; diff --git a/src/tablocations.ui b/src/tablocations.ui index c8b44ec..d537d38 100644 --- a/src/tablocations.ui +++ b/src/tablocations.ui @@ -38,7 +38,7 @@ - <html><head/><body><p>X:</p></body></html> + X: diff --git a/src/tabstructures.cpp b/src/tabstructures.cpp index b94437b..a0f53ac 100644 --- a/src/tabstructures.cpp +++ b/src/tabstructures.cpp @@ -257,19 +257,19 @@ bool TabStructures::event(QEvent *e) if (e->type() == QEvent::LayoutRequest) { QFontMetrics fm = QFontMetrics(ui->treeStructs->font()); - ui->treeStructs->setColumnWidth(0, fm.horizontalAdvance('#') * 23); - ui->treeStructs->setColumnWidth(1, fm.horizontalAdvance('#') * 17); - ui->treeStructs->setColumnWidth(2, fm.horizontalAdvance('#') * 6); - ui->treeStructs->setColumnWidth(3, fm.horizontalAdvance('#') * 7); - ui->treeStructs->setColumnWidth(4, fm.horizontalAdvance('#') * 7); - - ui->treeQuads->setColumnWidth(0, fm.horizontalAdvance('#') * 23); - ui->treeQuads->setColumnWidth(1, fm.horizontalAdvance("_quad-monument")); - ui->treeQuads->setColumnWidth(2, fm.horizontalAdvance('#') * 10); - ui->treeQuads->setColumnWidth(3, fm.horizontalAdvance('#') * 10); - ui->treeQuads->setColumnWidth(4, fm.horizontalAdvance('#') * 10); - ui->treeQuads->setColumnWidth(5, fm.horizontalAdvance("_123.123")); - ui->treeQuads->setColumnWidth(6, fm.horizontalAdvance('#') * 14); + ui->treeStructs->setColumnWidth(0, txtWidth(fm) * 23); + ui->treeStructs->setColumnWidth(1, txtWidth(fm) * 17); + ui->treeStructs->setColumnWidth(2, txtWidth(fm) * 6); + ui->treeStructs->setColumnWidth(3, txtWidth(fm) * 7); + ui->treeStructs->setColumnWidth(4, txtWidth(fm) * 7); + + ui->treeQuads->setColumnWidth(0, txtWidth(fm) * 23); + ui->treeQuads->setColumnWidth(1, txtWidth(fm, "_quad-monument")); + ui->treeQuads->setColumnWidth(2, txtWidth(fm) * 10); + ui->treeQuads->setColumnWidth(3, txtWidth(fm) * 10); + ui->treeQuads->setColumnWidth(4, txtWidth(fm) * 10); + ui->treeQuads->setColumnWidth(5, txtWidth(fm, "_123.123")); + ui->treeQuads->setColumnWidth(6, txtWidth(fm) * 14); } return QWidget::event(e); } diff --git a/src/tabtriggers.cpp b/src/tabtriggers.cpp index 23b0cda..3841f81 100644 --- a/src/tabtriggers.cpp +++ b/src/tabtriggers.cpp @@ -128,10 +128,10 @@ bool TabTriggers::event(QEvent *e) if (e->type() == QEvent::LayoutRequest) { QFontMetrics fm = QFontMetrics(ui->treeWidget->font()); - ui->treeWidget->setColumnWidth(0, fm.horizontalAdvance('#') * 24); - ui->treeWidget->setColumnWidth(1, fm.horizontalAdvance('#') * 30); - ui->treeWidget->setColumnWidth(2, fm.horizontalAdvance('#') * 9); - ui->treeWidget->setColumnWidth(3, fm.horizontalAdvance('#') * 9); + ui->treeWidget->setColumnWidth(0, txtWidth(fm) * 24); + ui->treeWidget->setColumnWidth(1, txtWidth(fm) * 30); + ui->treeWidget->setColumnWidth(2, txtWidth(fm) * 9); + ui->treeWidget->setColumnWidth(3, txtWidth(fm) * 9); } return QWidget::event(e); } diff --git a/src/util.cpp b/src/util.cpp index 295b225..2b60036 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -160,6 +160,19 @@ QString getBiomeDisplay(int mc, int id) return name ? name : ""; } + +int txtWidth(const QFontMetrics& fm, const QString& s) +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) + return fm.width(s); +#else + return fm.horizontalAdvance(s); +#endif +} +int txtWidth(const QFontMetrics& fm) { return txtWidth(fm, "#"); } +int txtWidth(const QFont& f, const QString& s) { return txtWidth(QFontMetrics(f), s); } +int txtWidth(const QFont& f) { return txtWidth(QFontMetrics(f)); } + RandGen::RandGen() { std::random_device rd; diff --git a/src/util.h b/src/util.h index 1cfc475..bcdda51 100644 --- a/src/util.h +++ b/src/util.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -64,6 +65,11 @@ QString getStartPieceName(int stype, const StructureVariant *sv); QString getBiomeDisplay(int mc, int id); +int txtWidth(const QFontMetrics& fm, const QString& s); +int txtWidth(const QFontMetrics& fm); +int txtWidth(const QFont& f, const QString& s); +int txtWidth(const QFont& f); + struct RandGen { RandGen(); diff --git a/src/world.cpp b/src/world.cpp index b999653..ec09108 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -853,8 +853,13 @@ QString QWorld::getBiomeName(Pos p) case LOPT_BETA_T_1: c = "T"; break; case LOPT_BETA_H_1: c = "H"; break; } - if (lopt.activeDisp()) - c += "." + QString::number(lopt.activeDisp()); + if (int disp = lopt.activeDisp()) + { + if (wi.mc >= MC_1_18) + c += QString::asprintf(".%d%c(%d)", (disp-1)/2, (disp-1)%2?'B':'A', disp); + else + c += "." + QString::number(disp); + } return c + "=" + QString::number(id); } QString ret = getBiomeDisplay(wi.mc, id); @@ -1157,6 +1162,7 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz, if (sshow[D_GRID] && gridspacing) { int64_t gs = gridspacing; + while (true) { long x = floor(bx0 / gs), w = floor(bx1 / gs) - x + 1; @@ -1248,7 +1254,7 @@ void QWorld::draw(QPainter& painter, int vw, int vh, qreal focusx, qreal focusz, for (Shape& s : shapes) { - if (s.dim != dim) + if (s.dim != DIM_UNDEF && s.dim != dim) continue; qreal x1 = vw/2.0 + (s.p1.x - focusx) * blocks2pix; qreal y1 = vh/2.0 + (s.p1.z - focusz) * blocks2pix;