Bay 12 Games Forum

Dwarf Fortress => DF Modding => Utilities and 3rd Party Applications => Topic started by: PatrikLundell on February 22, 2018, 04:16:39 am

Title: DFHack plugin embark-assistant
Post by: PatrikLundell on February 22, 2018, 04:16:39 am
This plugin is included in DFHack but is actively invoked by the player and is used during pre embark to find desirable embark locations using an enhanced embark finder.

The plugin provide transparent overlays over the World, Region, and Local maps, an embark finder, an info/help screen, and a list of resources within the current embark rectangle under the Local map.

The plugin now takes "incursions" into account where deemed relevant, i.e. bits of biomes belonging to neighboring Mid Level Tiles that carve out a bit of area in a tile. This means that a single tile can have more than one biome on it, for instance.

The embark finder acts as a replacement for the vanilla finder and allows you to find embarks that match a combination of criteria:
- X/Y dimension of the embark
- Low/Medium/High savagery with values N/A, All, Present, Absent. Incursions are accounted for.
- Good/Neutral/Evil with values N/A, All, Present, Absent. Incursions are accounted for.
- Aquifer with values to handle all combinations of No/Light/Heavy aquifers.
- Min/Max River with values N/A, None, Brook, Stream, Minor, Medium, Major
- Waterfall with values N/A, Yes, No
- Flat with values N/A, Yes, No. Incursions are accounted for.
- Clay/Sand/Flux/Coal with values N/A, Present, Absent
- Min/Max Soil with values N/A, None, Very Shallow, Shallow, Deep, Very Deep
- Min Soil Everywhere with values All/Present
- Blood Rain, with values N/A, Yes, No. Incursions are accounted for.
- Syndrome Rain, with values N/A, Any Syndrome, Permanent Syndrome, Temporary Syndrome, Not Permanent Syndrome, No Syndrome. Incursions are accounted for.
- Reanimation with values N/A, Reanimation & Thralling, Reanimation or Thralling, Thralling, Reanimation, Not Thralling, None. Incursions are accounted for.
- Min/Max Adamantine Spire Count with values N/A, 0-9
- Min/Max Magma with values N/A, Third Cavern, Second Cavern, First Cavern, Volcano
- Min/Max Biome Count with values N/A, 1-9. Incursions are accounted for.
- Region Type 1/2/3 with value N/A plus all the Region types (e.g Jungle). Incursions are accounted for.
- Biome 1/2/3 with value N/A plus all the surface biomes. Incursions are accounted for.
- Min/Max Tree coverage with values N/A, Very Scarce, Scarce, Woodland, and Heavily Forested. Incursions are accounted for.
- Metal 1/2/3 with value N/A plus all the ore derived metals
- Economic 1/2/3 with value N/A plus all the economic stones
- Mineral 1/2/3 with value N/A plus all the minerals (which includes the economic ones)
- Min/Max necro neighbors, with values N/A and 0-16
- Min/Max civ neighbors, with values N/A and 0-number of civilized entities - 1 (your own entity isn't counted)
- Each potential civ neighbor, with values N/A, Absent, and Present.

Each criterion forms a requirement that has to be met by an embark. The terminology above is:
- N/A: This criterion is not used
- All: Every tile of the embark has to fulfill this criterion
- Present: The condition has to be met by at least one tile of the embark
- Absent: The feature mustn't be present in any tile of the embark
- Partial: The feature has to be present on the embark, but mustn't cover all tiles
- Not All: The feature mustn't cover all tiles, but may be completely absent

Soil is a bit convoluted. Min Soil Everywhere is a modifier of Min Soil. If Min Soil is N/A it has no effect, but if Min Soil has a value it specifies whether the Min Soil criterion has to be met by every tile in the embark, or if it's sufficient that it's met by at least one tile.

All criteria that exist in a Min and Max version obviously result in a complete failure to find any compatible embark if Max is less than Min, but a N/A value for one (or both) of them is OK, as that value does not add any additional restrictions.

The Savagery and Evilness criteria are designed to allow for selection of combined embarks, e.g. an embark that has some Good and some Evil on it.

One a selection profile has been set up, "find" starts a search, which takes some time (which is the reason it has to be a plugin rather than a script: it's slow enough when compiled). The results are overlays on the World and Region maps showing where matching embarks exist, plus an overlay on the Local map that shows the embarks within that region that fulfill the criteria (represented by the top left corner of the embark). A search can be canceled while underway, resulting in a partial search result, in case you don't want to wait for the complete one.

As a minor bonus functionality, the Local map overlay also shows any sites DF doesn't display that happen to be present on the Local map. Neighbors are also shown, mainly because it allows the listing of Kobolds, which are hidden by the vanilla display.

It can be noted that the resources indicated by Embark Assistant for embarks can differ from what DF displays for two reasons:
1. DF displays resources for the region displayed, not the combined resources of the embark, so switching regions (F1-F9) shows different subsets of the available resources.
2. DF does not take elevation based erosion into account, nor does it handle resource cutoff due to the location of the magma sea. This means that it can display the presence of clay or aquifers where none is present, as well as flux and deep metal(s) that are not present because they would have appeared deeper than the magma sea.

Note that the plugin uses 47 lines to display all search criteria, but the list is scrolled, so a shallower window can still be used.

Usage:
The plugin is actively invoked from the DFHack console window by typing "embark-assistant" (minus the quotes) when the pre embark world is displayed. It can be exited at any time using 'q' from the main view (in which case it can be restarted from the console), although you abort the finder and the info screens with ESC to get back to the normal level.
Embarking will also dismiss it, as will exiting the pre embark screen from the vanilla DF menu reached with ESC.
Note that the info/help is spread over several pages cycled over with TAB/shift-TAB.

The author intends to edit this post without explicit change marks to reflect changes in the functionality/improved descriptions.
Title: Re: DFHack plugin embark-assistant
Post by: Roses on February 22, 2018, 01:24:51 pm
Looks great, I'll have to test it out this weekend.
Title: Re: DFHack plugin embark-assistant
Post by: xyzzy on February 23, 2018, 12:19:26 pm
I tried this last night and it works great and is very useful.   Thanks!
Title: Re: DFHack plugin embark-assistant
Post by: jecowa on February 23, 2018, 12:43:59 pm
Does it tell you what specific type(s) of metal is in the embark, or is that kept hidden to make it a surprise?

If I search for a partial aquifer, would that give me an embark rectangle with at least 1 aquifer square and at least 1 non-aquifer square? That sounds pretty cool.
Title: Re: DFHack plugin embark-assistant
Post by: xyzzy on February 23, 2018, 12:50:41 pm
I only used it briefly, so there may be more options I haven't seen yet, but the specific types of metal ores seem hidden - i.e. you can search for iron and it highlights the map where it's found but it doesn't specify whether it's hematite, magnetite, or limonite.   

I'm very excited that it finds waterfalls - I've been wanting to do a waterfall embark but I have trouble finding them on the map on my own.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on February 23, 2018, 01:57:59 pm
The current embark rectangle info shows a list of exactly the metals and economic stone (plus clay and sand) available in that rectangle (assuming it works as intended: I haven't found any bugs [that I haven't fixed], apart from the reanimating one (which is going to be corrected within the next few days, although being a plugin means it won't be available until the next DFHack release after the update has been accepted): the Biome Manipuator can be used to check if a match is correct or not), and the search allows you to search for specific metals, their ores, or a mixture, so there's no hiding. The embark info shows the metal, though, not the ore, as that's usually not of interest, and it just shows a generic clay indicator, so you'd need to search to narrow it down to fire clay.

And yes, Partial means 1 .. (All - 1) tiles (Present means at 1+ tiles), intended in particular for aquifers.
Title: Re: DFHack plugin embark-assistant
Post by: xaldin on February 23, 2018, 07:20:27 pm
This is a really nice utility. I don't suppose there is a way to add volcanos/magma within a certain range of surface into it?  I miss being able to search on criteria with volcanos from the older versions of DF. Particularly I recall finding surface or near surface magma more frequently with that.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on February 24, 2018, 02:31:15 am
One of the purposes of this thread is to pick up suggestions for improvements...

I haven't played DF before 0.40.X, so I have little idea of what they looked like. I don't know off hand how to locate volcanoes, but it ought to be doable. Magma pipes can probably be located, but I don't know how precise the info on depth is. A guess would be that the info is what the highest cavern reached is, rather than an actual depth in Z levels.
Title: Re: DFHack plugin embark-assistant
Post by: xaldin on February 24, 2018, 10:43:07 am
One of the purposes of this thread is to pick up suggestions for improvements...

I haven't played DF before 0.40.X, so I have little idea of what they looked like. I don't know off hand how to locate volcanoes, but it ought to be doable. Magma pipes can probably be located, but I don't know how precise the info on depth is. A guess would be that the info is what the highest cavern reached is, rather than an actual depth in Z levels.

A true designated volcano I would think would be like finding streams or other map level objects since they show up on the world map themselves.
 
Non designated volcanoes and instead looking for high magma would be the hard one. Caverns and magma aren't always linked it appears. Some of that may be the weird world gen parameters I put in so needs validation from others. I can find magma below the 3rd cave system on some maps and above the first on others. Volcanoes can sometimes be way above the ground level and other times top out below it. Once in a blue moon it used to be possible to find one that opened at the surface level itself but that has gotten super special rare now if they even happen anymore. 

Obsidian surrounds the magma pipes; that may be a detection method if the magma itself is hard to detect. That may be easier to target than the liquids.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on February 24, 2018, 12:14:53 pm
I believe I've found the missing pieces for locating volcanoes, magma tubes, and adamantine spires (as well as pit and connections between cavern levels, but those are probably not of interest).

You can't detect volcanoes or magma pipes by looking for the obsidian sheath, because the sheath is generated by the volcano/tube, and none of the in game map level features have actually been generated prior to embark.
Magma tubes are defined to reach cavern 1, 2, or 3, as I thought.

To get technical, the volcanoes etc. are stored in a structure called feature map, but that info only tells you which world tile they reside in (plus the level some things, such as magma pipes and adamantine spires reach), but not where within the world tile they are to be placed. The region_details structure, however, contains references to all features (in the feature_map) present for each mid level tile (plus caverns and the magma sea), so it's a matter of putting this info together. I haven't yet verified that it's actually correct, but the candy spires showed up in the correct pattern when mapping it out on paper, so it's a fair bet it works.
Title: Re: DFHack plugin embark-assistant
Post by: xaldin on February 24, 2018, 12:57:24 pm
Awesome sounds like you have everything for the old volcano search function that used to exist.  Now for another idea: Is it possible to add nearby feature to the finder? Meaning say only show me sites that show goblins near, or sites that show a necromancer tower near?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on February 24, 2018, 02:59:26 pm
It's technically possible, but it would require quite a lot of additional code for it to be useful, which might slow things down further. This kind of info doesn't use any of the data currently used, so it would be some kind of final filter after everything else is done, and going though each site in the world for every world tile isn't that appealing. Add the need to check that there is a path (not on another continent or a mountain range in the way, and compute the path to ensure it's short enough), and probably that the site actually contains a reasonable number of warm/cold bodies to throw at you and it gets messy. It's probably something better done with the old Mk I Eyeball and Legends Mode info.
I go for the dark fortresses and ensure they the closest gobbo site to my embark, that no other of my civ's site are within their range (easy, as I play dead civs), and that there aren't other civ sites that are closer. Also, Legends info is needed to check the gobbos actually are in control and have reasonable numbers.
Title: Re: DFHack plugin embark-assistant
Post by: xaldin on February 24, 2018, 04:31:00 pm
Ok fair enough on that. How about these ideas: 

Saving your search criteria for import that way I don't have to redo all the various criteria each time? 
Marking the tiles with auto created notes so that the results are effectively saved if you embark once? It'd keep one from having to redo the search or manually go mark all possible spots first before embarking.  Only one would be needed per 16x16 I think.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on February 24, 2018, 05:26:45 pm
Import/export of the search profile might be possible (with the usual headache of juggling different versions).
Notes is probably not a good idea, because in the general case you need to know exactly where the embark locations were; being told that somewhere within this world tile is one or more locations that matches your previous criteria isn't that useful (in particular if you don't remember what those criteria were) and would cause a lot of clutter. Also, if you found the previous embark to be lacking, you may want to embark in a copy of the original world rather than retiring and re-embarking.
Title: Re: DFHack plugin embark-assistant
Post by: xaldin on February 24, 2018, 07:06:59 pm
Amusingly the scenario you outline is kind of what I do just with world copies. I build a copy with Scout on it that I embark, look around, abandon then do again until I find a spot I like then go and embark on the pristine world.

So yeah notes probably a bad idea, thought more about it myself and went 'oh that could go horribly wrong'. Still I kind of like the ability to import/save queries. Even if it is just 'remember last one done' would be excellent in my opinion.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on February 25, 2018, 03:12:10 am
When it comes to search profile saving, I'm considering an active implementation, i.e. save and load actions (or export/import, or whatever names seem suitable given available command keys, etc.). The data would be saved into a file with a fixed name, so if you want multiple profiles you'd have to juggle that by renaming the files.
Title: Re: DFHack plugin embark-assistant
Post by: xaldin on February 25, 2018, 11:05:25 am
When it comes to search profile saving, I'm considering an active implementation, i.e. save and load actions (or export/import, or whatever names seem suitable given available command keys, etc.). The data would be saved into a file with a fixed name, so if you want multiple profiles you'd have to juggle that by renaming the files.

That would be everything I had envisioned or need honestly.
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on February 25, 2018, 07:55:56 pm
This is a really nice utility. I don't suppose there is a way to add volcanos/magma within a certain range of surface into it?  I miss being able to search on criteria with volcanos from the older versions of DF. Particularly I recall finding surface or near surface magma more frequently with that.
I don't remember that ever being a vanilla feature - what version was that?
Title: Re: DFHack plugin embark-assistant
Post by: TheBeardyMan on February 27, 2018, 07:36:47 am
This is a really nice utility. I don't suppose there is a way to add volcanos/magma within a certain range of surface into it?  I miss being able to search on criteria with volcanos from the older versions of DF. Particularly I recall finding surface or near surface magma more frequently with that.
I don't remember that ever being a vanilla feature - what version was that?

Version 40d (http://dwarffortresswiki.org/index.php/40d%3AMain_Page)'s site finder had options to select sites with a magma pool and/or a magma pipe among the few subterranean features (the only others were one underground pool, one underground river, one chasm, one bottomless pit, and HFS) that existed back then.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on March 15, 2018, 03:27:46 am
Version 0.3 2018-02-26 is included in DFHack 0.44.07-alpha(dev). This means it can be accessed, but the primary purpose of that DFHack version is DFHack development, not game play.
The new version contains the following changes:
- Added adamantine spire count search criteria.
- Added magma detection criteria. This can search for magma pools and/or volcanoes.
- Corrected a bug in reanimated biome detection.
- Saving/loading of search criteria from/to a file.
- Required window height increased to 46 (to fit the new search criteria in).
Title: Re: DFHack plugin embark-assistant
Post by: ltwass on March 16, 2018, 09:18:43 am
Can I make a suggestion for the embark-assistant? Or maybe this doesn't fall under its scope, idk.

Give us an option for a random embark location. Just plop the fort down somewhere in the world and good luck surviving in whatever conditions are there.  Frozen evil biome with no metals?  Good luck.  Temperate hill country with an aquifier?  Better start checking the wiki.

I know nothing prevents us from doing that by throwing a dart at our monitor, but it would seem to be more reflective of the Will of Armok if the computer generated one for us.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on March 16, 2018, 12:14:55 pm
Since the purpose of the plugin is to find things, NOT finding thing is in the complete opposite direction.
It shouldn't be hard to write a script that just randomized the world tile and upper left corner of the embark rectangle, and then moved the embark rectangle there. Optional to also check it isn't all water...
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 02, 2018, 09:12:53 am
Just discovered this and it is super cool, thank you!

Would it be possible to expand slightly on the metal/econ/mineral filters to allow for some simple boolean logic? i.e. "bituminous coal OR lignite" would be a common one to search for fuel sources, or "iron OR (copper AND tin)" to require either iron or bronze for military use.

I realize the menuing system isn't ideal for this purpose, but if you can dynamically add and remove entries then you could maybe do something like this, supporting only a two-level logical clause but presenting more slots as they're used up:

Code: [Select]
Metals 1       N/A
Economics 1    N/A
Minerals 1     N/A

Code: [Select]
(
Metals 1       IRON
Metals 1       N/A
) OR (
Metals 2       N/A
)
Economics 1    N/A
Minerals 1     N/A

Code: [Select]
(
Metals 1       IRON
Metals 1       N/A
) OR (
Metals 2       COPPER
Metals 2       N/A
) OR (
Metals 3       N/A
)
Economics 1    N/A
Minerals 1     N/A

Code: [Select]
(
Metals 1       IRON
Metals 1       N/A
) OR (
Metals 2       COPPER
Metals 2       TIN
Metals 2       N/A
) OR (
Metals 3       N/A
)
Economics 1    N/A
Minerals 1     N/A

edit: Also, the finder results seem presented in a slightly confusing way. It says "Matching World Tiles" but in fact that seems to be a tally of matching *Region* tiles, not World tiles, and it is only on the Region map that tiles are highlighted, not on a World map, which can make results a little harder to locate in the world. It'd be great if the tally said "Region Tiles" and if the World map also had blinking markers for found sites.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 02, 2018, 01:46:26 pm
I don't think it would be easy to get those alternatives in.
Part of the problem is to retain RAW independence, i.e. have the plugin derive categories from the RAW contents, rather than hard code what they are. It would probably be easier to introduce a Fuel category, although I can't say offhand if there's an easy way to determine whether an input is fuel or part of the product (reactions are messy, with poor indications of what's what).
It's even harder for your metal case, as you're not satisfied with just any weapons grade metals, but only want the top ones (and silver can be argued to be the "best" one for blunt weapons at that). Leaving it up to the user to "build" the the lists would obviously remove the burden from the tool to determine what to look for, but at the cost of building some convoluted Boolean logic construction UI. It can also be noted that coal is represented by several mineral, while metals are derived from (potentially) several mineral, so it wouldn't be possible to combine minerals and metals at the same time.

The Matching World Tiles should be that, i.e. the number of world tiles that have at least one match in them. The number starts high as the first pass counts all tiles that are not incapable of having a match (e.g. requiring clay, and there's no clay in any of the mid level tiles). The detailed pass then removes the ones that do not have any match in them.
Unless there's a bug, each matching world tile should be marked on the middle map (the one labeled "Region" by DF), first with a yellow "X" after the tentative pass, and then a green one when the final check has been made (assuming there was a match: otherwise the marker is removed, of course). If those markers are missing, there's a bug somewhere.
It can also be noted that there are more yellow markers on the first search than on subsequent ones: that is not a bug, but a result of detailed examination of tiles carrying some info back to the preliminary phase data (it starts out based only on what the geo biome of that world tile and its surrounding tiles have, but e.g. in the case of clay, if one adjacent world tile has clay, the tile would not be marked as "definitely no clay", but if a detailed examination showed there wasn't any (due to erosion or no mid level tiles having that neighboring tile's geo biome), the info is updated to "no clay present".

The reason there are no indications on the World map (the rightmost one) is that I haven't been able to replicate the logic DF uses to squash multiple tiles into one for display: I've come fairly close, but that's not good enough.
Title: Re: DFHack plugin embark-assistant
Post by: Meph on August 02, 2018, 02:02:34 pm
Will your embark-assistant and region manipulator be bundled into the main dfhack release?

I'd love to add them to my launcher, maybe have them automatically started from an onload.init, but I'd rather avoid them if they lack behind up-to-date dfhack releases. :/
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on August 02, 2018, 02:45:44 pm
embark-assistant has been since 0.44.05-r2
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 02, 2018, 02:50:36 pm
lethosor answered while I typed...

Embark Assistant is a plugin that's part of DFHack currently (and has never been made available outside of DFHack), as that's the only reasonable way to provide a plugin if you don't want to support development environments for multiple OS', and it's too CPU resource intensive to be viable as a script (it's slow enough as a plugin: it takes more than an order of magnitude longer as a script). Others have already made some minor changes to the Embark Assistant, by the way.
However, I don't like github as I find it a pain in the posterior (I still use it when I have to, e.g. for DF structure research results and DFHack script fixes), and the DFHack release tie means the turn around cycle for bug fixes and enhancements is longer than I like, so I use scripts when I can (it took 4 months from me submitting a Pull Request for the Embark Assistant to it being accepted in the first place).
I intend to support my scripts as long as they're relevant, although at some time in the future I'll obviously leave the community (they'll eventually put the lid on the coffin, if nothing else). However, the Myth & Magic release will certainly play a number on most everything, so we'll see what can be salvaged at that point. I currently have no plans of leaving the community, and the Big Wait isn't far away, and when that starts there won't be much in the way of changes that would disrupt things. If DFHack research results in (re)naming of used fields I intend to adapt to it.
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on August 02, 2018, 09:04:45 pm
I am fast sometimes. For the record, most of that 4-month delay was my fault - I was busy during that time, didn't get around to looking at PRs, and didn't ask anyone else with repo access to look at them either. (Of course, partly due to that, there weren't many DFHack releases during that time either.) Chances are that'll happen again in some form, so I'll try to be more clear about that. (And better GitHub docs are still on my list of things to do... it's beneficial for us when tool authors like you are comfortable with it, because it tends to make it easier for you to merge our changes back into your version, decreasing the chance that they'll be overwritten, etc.)

I'm unfamiliar with the region manipulator / biome manipulator / etc. family of tools. If you think distributing them with DFHack would be beneficial, I can help look into that.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 03, 2018, 03:03:38 am
I don't have a version of embark-assistant... I work from whatever is on Github, as juggling multiple versions just for the sake of it is rather pointless, so any merging issues comes from concurrent changes.

I don't blame lethosor for being subject to Real Life, just commenting on the fact that such impacts propagate (at least until such a time the DFHack juggling tasks are spread over half a dozen people or so, which would add its own level of management complexity).

For me personally it's a lot easier to not involve DFHack itself unless it's necessary, as it just adds overhead, so in the case of my manipulation/view scripts, I prefer to keep them on the outside unless I'm performing some kind of controlled exit from the scene (In the case of an uncontrolled exit: I have no objections to an inclusion, as the scripts are intended to be used). I haven't had any indication of others having a burning urge to modify the scripts themselves, so I don't think there's any version control benefit either.
Title: Re: DFHack plugin embark-assistant
Post by: clinodev on August 03, 2018, 04:02:16 am
I love this plugin, and I recommend it whenever it's remotely appropriate.

I have something of an addiction to DF streams on Twitch, and have cajoled it's demonstration on camera a number of times. I tell them "If you want an evil savage reanimating forest with iron, coal, emeralds, and magma by the second cavern at worst, it's no problem, as long as it exists, this will find it!

On a more personal level, I prefer mountain embarks, (6-8 tiles of a 3x3 when possible,) and they tend to be iron poor. Previous to this plugin being pointed out to me, I had to do much tedious and repetitive adjusting the embark, prospect all, adjust again, and so on before finding a suitable site (and most of those half covered in laggy trees.) Now almost all of that labor is gone, with all the best sites merrily marked for me to make my choice from, and I can get on with the game!

Thank you very much for your efforts!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 03, 2018, 05:15:01 am
Thanks for the kind words, clinodev. The whole purpose of this kind of tools is to allow people to get to the game bit by reducing the trial-and-error bit, and philosophically I'm more into handing people fishing rods so they can fish for themselves than giving them fish.
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 03, 2018, 09:15:24 am
I don't think it would be easy to get those alternatives in.

Fair enough, maybe not worth the effort. Just thought I'd pitch the idea in case it was feasible, since I imagine folks could put it to a number of uses, not just my weapons metal and fuel examples.

The Matching World Tiles should be that, i.e. the number of world tiles that have at least one match in them. The number starts high as the first pass counts all tiles that are not incapable of having a match (e.g. requiring clay, and there's no clay in any of the mid level tiles). The detailed pass then removes the ones that do not have any match in them.
Unless there's a bug, each matching world tile should be marked on the middle map (the one labeled "Region" by DF), first with a yellow "X" after the tentative pass, and then a green one when the final check has been made (assuming there was a match: otherwise the marker is removed, of course). If those markers are missing, there's a bug somewhere.
I think my confusion comes from the mismatching terminology. You're using "world tile" to refer to a tile on the middle map, and yes, that's the one where I see initial yellow Xs and final green Xs, and the number of those Xs does indeed match what's reported by the plugin on the right. The thing is, DF itself labels the middle map "Region" and the right map "World", while your plugin refers to the middle map as "World". So just changing the text to be "Region Tiles" would avoid the confusion. (I get that in the DF mod dev world there are various conventions for referring to world/region/local/fortmode tile zoom levels, but from the user perspective all they know is what labels are shown on-screen, so it's weird when those don't agree with eachother.)

The reason there are no indications on the World map (the rightmost one) is that I haven't been able to replicate the logic DF uses to squash multiple tiles into one for display: I've come fairly close, but that's not good enough.
From my very limited experimentation it seemed to me that it just depends on world size. In a "small" world there seem to be 2 region tiles per world tile; "medium" has 3, "large" has 5. I think. But I guess maybe they're not evenly divisible? I guess that'd be easy enough to test by just counting the dimensions of each map for each world size. Anyway, yeah, it's that right-hand world map that would be great to get Xs on; right now in a medium or large world if your search turns up just a few results, it takes awhile to hunt around and find them on the region map.

EDIT: Okay, did some testing, of course it's not so simple. The world map displayed size appears to depend on the window size, so for example for me a "small" world in a maximized window has a 32x32 world map, but if I shrink the window down DF will eventually switch to a 22x22 world map to leave more room for the region map. However, the mapping of region tiles to world tiles seems to be consistently simple: if the dimensions don't divide evenly, any extra region tiles are folded into the east-most column and south-most row of the world map. For example, here are the dimensions I checked at my maximized resolution:

Code: [Select]
size    region  world  ratio  distribution
------  ------  -----  -----  ------------
Pocket    17      17    1     1,1,...,1
Smaller   33      33    1     1,1,...,1
Small     65      32    2.03  2,2,...,3
Medium 129      43    3     3,3,...,3
Large 257      51    5.04  5,5,...,7

The Pocket, Smaller and Medium dimensions all divide equally so each world map tile represents the same number of region map tiles, but in the Small and Large worlds the mapping was 2:1 and 5:1 respectively for all but the last row/column, where it was 3:1 and 7:1 to round out the leftovers.

So I think if you're able to detect the displayed world map dimensions at any given time, you can convert a region coordinate to a world coordinate like so (using integer division with implicit FLOOR):

Code: [Select]
worldX = MIN(regionX / (regionW / worldW), worldW - 1)
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 03, 2018, 11:00:01 am
I'm trying to move away from using the term "Region" because of terminology confusion. However, a World Tile is a fairly established terminology for the actual top level tiles in the world: those are the tiles you actually move between on the world level. The fact that DF's World display squashes those into a smaller number based on display size doesn't change the underlying technical entity. Calling those Region Tiles would definitely confuse things as that term is usually used to refer to Mid Level Tiles (the ones on the Local map), but not always, and not by everyone.

I tried a number of different matches for the squashing, including leaving the "remainder" at the end, and almost, but not quite, managed to get it to match as I resized the game window with different sized maps. The logic has to cover any size world (ideally including non standard ones) combined with any window size (at least down to the default one). I failed to predict when DF would switch resolution, for instance: being correct to within 1 isn't good enough.
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 03, 2018, 01:39:28 pm
I understand where you're coming from and I don't want to keep arguing the same point, but let me just state the case this way and leave it at that: the broader user base doesn't know (and, I think, shouldn't have to know) what the game's world data structures look like or that the right-hand map tiles aren't actually "real" but are just sampled on the fly from a varying area of "real" top-level tiles from the center map. What the broader user base knows is that the center map is labeled "Region", the right-hand map is labeled "World", and the wiki agrees with that terminology by i.e. referring to world sizes by their "region tile" dimensions (http://dwarffortresswiki.org/index.php/DF2014:World_generation#World_size). So I get that using the label "Matching Region Tiles" maybe feels icky to an internals developer who knows why that's kind of a misnomer, but to the general user base it would be far more sensible and intuitive than the current situation where the label "Matching World Tiles" actually refers to what's under the "Region" header and not what's under the "World" header. And I think power users will still grok what the label means, especially if you're ever able to crack the scaling so you can put up a second tally of "Matching World Tiles" referring to the right-hand map.

On that topic, is it necessary to predict when DF will switch world map resolution, or could it be measured empirically? For example does dfhack let you read the current contents of the screen in order to find the "World" header, go down to the top left glyph of the map, and then go right and down looking for blank spaces to measure its size? Or, does your mechanism for rendering the Xs on the region map and the hotkey prompts in the right-edge text area let you know the screen coordinates of those things, in order to calculate the gap between them where the world map must be?

Just brainstorming ideas. I'll do some more testing to see if I can find a formula that holds up to resizes.
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 03, 2018, 03:28:33 pm
Okay, I think I understand now how the world map dimensions are chosen and how region tile coordinates are mapped to world tile coordinates based on the region map's displayed dimensions (which in turn of course depends on the console/screen dimensions). So to state it as a formula I just need to know what information you have easy access to from the dfhack API on your end, and what kind of coordinates (screen col/row? worldmap X/Y? something else?) you need to draw the Xs.

Can you read the current displayed dimensions of the (center) region map, or only the total console size? And can you write X markers to the (right) world map using an offset from the top-left corner of that map, or do you need to offset from the top-left of the region map, or of the whole console?

Also, I did my testing using the available default world sizes (17-33-65-129-257 region tiles), but you mentioned custom worlds. I went into the "design a world with advanced parameters" but could not find any way to specify alternate sizes (i.e. 256), I could only select the width and height (separately) from among those 5 presets. Is there some hack to force world gen with an arbitrary size?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 03, 2018, 05:30:08 pm
I understand what you're saying, and I agree that something should be done about the terminology so it's both understandable for "casual" users and doesn't clash with what's "known" by power users. I'll need to think about that.
Hm, "World Map (right) Tiles", "Region Map (middle) Tiles" might work, if there's enough screen real estate for the text (always in short supply).

In order to merge the info to the correct place on the "World" map I need to be able to determine exactly which (technical) World Tiles go onto exactly which "World map" merged tiles. It's preferable to use world X/Y dimensions and screen dimensions (which are readily available) to do that, although it should be possible to read the contents of a "screen tile" for empirical measurement (I know it can be done from Lua scripts, so the same underlying function should be usable from High Level Assembly (a.k.a. C(++)).

I don't need to read the dimensions of the center map, as I've got the logic for what it will be sorted out, so it is computed based on the basics, i.e. world and screen size. If I remember correctly, the logic for where the top left corner of the right map ends up is also in place.

There are two kinds of custom world sizes. The "simple" one is different dimensions for X and Y (I typically use 17 * 129, for instance), and the "complicated" one is whacko dimensions (e.g. 25*42, randomly selected). The first one can easily be generated with the standard advanced world gen interface (as you've seen), as well as using a saved template (with optional PSV data). I'm not quite sure if whacky sizes can be done by modifying the template file, or if you need to use DFHack to change them, but I think a template is enough. I don't think any special handling is needed for differing standard X/Y dimensions, though, as they ought to just follow the normal logic for the appropriate dimension.

Edit: I'm going to make a new attempt at matching World Tiles to the DF World Map. This is what I left behind when I gave up a year ago:
Spoiler (click to show/hide)

Edit 2: The other part from the code:
Spoiler (click to show/hide)

Edit 3:
I think I've found how DF decides to resize the map (haven't tried non standard dimensions, and mostly the Y dimension) (Lua script this time):
Spoiler (click to show/hide)
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 04, 2018, 01:36:21 pm
Yep, I think you found the same little quirk I did -- the ratio is based on (totalsize - 1) / (availsize) rather than totalsize / availsize as one might expect. The X and Y dimensions appear to be handled independently, so all these formulas are axis-agnostic:

Code: [Select]
realTiles = "number of real top-level tiles in the world in this dimension, i.e. 17, 33, 65, 129 or 257 for standard worlds"
regionTiles = "number of displayed (center) region map tiles in this dimension; dependent on window size"
normalWorldScale = "ratio of displayed (right) world map tiles to (center) region map tiles for all columns/rows except the last" = CEILING((realTiles - 1) / regionTiles
worldTiles = "number of displayed (right) world map tiles in this dimension" = MIN(regionTiles, CEILING(realTiles / normalWorldScale - 0.5))
finalWorldScale = "ratio of displayed (right) world map tiles to (center) region map tiles for only the last column/row" = realTiles - (worldTiles - 1) * normalWorldScale
regionCoord = "offset to a position in the (center) region map, from 0 to realTiles - 1"
worldCoord = "offset to a position in the (right) world map, from 0 to worldTiles - 1" = MIN(worldTiles - 1, FLOOR(regionCoord / normalWorldScale))

I gathered data on all five standard map dimensions and window sizes from 25 to 120ish and found the region map size breakpoints where the world map would resize, and these equations match what I observed for all cases. Some of the components look a little odd but may be the result of Toady writing the code using slightly different inputs or operators; for example "realTiles - 1" is also "maxRegionCoord" so maybe that's the value he had on hand and neglected to add 1 for the 0th position, and CEILING(X/Y - 0.5) is effectively ROUND_HALF_DOWN(X/Y) (i.e. round to nearest, but 0.5 toward 0 instead of away).

Anyway, let me know you find a case where those values come out wrong and I'm happy to tinker with it some more!
Title: Re: DFHack plugin embark-assistant
Post by: Bumber on August 04, 2018, 05:28:40 pm
What does Toady call region tiles? It was something amusing, but I forget.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 05, 2018, 03:27:56 am
What does Toady call region tiles? It was something amusing, but I forget.
Mid Level Tiles, if you use the most common interpretation of "region tile". That's the one I use since then, as it ought to be unambiguous. The most amusing term is probably "feature shell" though.

@taleden: I went through all cases vertically up to and including 129, predicting the 257 size map beforehand and verifying that the changes occurred where predicted. I'll make a few tests with weird map sizes to see what happens. Axis agnosticism is handy, and matches what I've seen.

Edit: Hmpf! When testing I found DF behaving weirdly with a 129 Y dimension world: it changed the scale factor at 19 and 22 available lines as expected, but weirdly it only uses 18/21, leaving the World map one tile shorter than the Region one (and a lot of World Tiles mapped onto the tiles of the last row). Thus, I need to test through each world size carefully for each dimension to see if there are other such cases. Also failed to generate weirdly shaped worlds, although I know I have done so a few years ago.
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 05, 2018, 08:29:07 am
Edit: Hmpf! When testing I found DF behaving weirdly with a 129 Y dimension world: it changed the scale factor at 19 and 22 available lines as expected, but weirdly it only uses 18/21, leaving the World map one tile shorter than the Region one (and a lot of World Tiles mapped onto the tiles of the last row).

Yes, I observed this as well, and at least the cases I saw are handled by the equations I posted. For example with world size 129 and (center) region map heights from 22-25, the (right) world map has height 21, leaving its bottom row blank. The mapping in that case is 20 rows of 6:1 and the final row 9:1. But the equations should handle that:

Code: [Select]
normalWorldScale = CEILING((realTiles - 1) / regionTiles = CEILING((129 - 1) / 22) = CEILING(5.82) = 6
worldTiles = MIN(regionTiles, CEILING(realTiles / normalWorldScale - 0.5)) = MIN(22, CEILING(129 / 6 - 0.5)) = MIN(22, CEILING(21.5 - 0.5)) = MIN(22, CEILING(21)) = 21

So I think in fact it's exactly the round-half-down behavior I mentioned that causes these odd results with unused space in the (right) world map.

edit: It would be nice to have integer-math versions of these equations to make sure to avoid any floating point oddities. If I have some time later I'll give that a try, but in the mean time since we know the size of the values we're working with is small we can probably get away with just adding some manual fuzz, i.e. "CEILING(X - 0.5001)".
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 05, 2018, 09:55:14 am
Assuming I've gotten it right, the following ugly (Lua version) logic should take care of it (and I'm giving up on odd sized worlds):
Spoiler (click to show/hide)

As expected, I don't have enough room for a good matching description, so I've ended up with:
Matching World Tiles: xxx
(Those on Region Map)

Not great, but might be a bit better. Curiously, counting the number of tile on the right map would require extra work, as the logic currently just writes an X in the right place when iterating over all World Tiles without checking if there is one already. It's easier to count the ones on top of the Region map, as that would just be a matter of summing up how many times an X is written, but I don't think that would add anything to what the Eyeball Mk 1 tells you.


Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on August 05, 2018, 10:18:14 am
Footnote on odd sized worlds: I had to use dfhack's gui/gm-editor to make them, personally (also had to have a prompt popup i.e. with initial vanilla size change to initialize the values for it to work for some reason). But that was a while ago, much like you.
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 05, 2018, 12:36:00 pm
I managed to massage the equations to work out with integer arithmetic (i.e. no more CEILING, no non-integer constants, implied FLOOR on all divisions):

Code: [Select]
normalWorldScale = (realTiles - 1 + regionTiles - 1) / regionTiles
worldTiles = MIN(regionTiles, ((realTiles + ((normalWorldScale - 1) / 2)) / normalWorldScale))

edit: So, no need for an iterative algorithm, or I think for any hard coded special cases for certain combinations of world sizes and scale factors; just plug the above equations in (using integer math) and they should get the right numbers. I think there's a good chance they'll work for non-standard world dimensions as well, since this new integer variant seems much more plausible to me as something Toady might well have written (again allowing for plausible quirks of the variables he had available at the time, i.e. maxCoord rather than numTiles-1 as I've written it above).
Title: Re: DFHack plugin embark-assistant
Post by: Bumber on August 05, 2018, 04:37:52 pm
The most amusing term is probably "feature shell" though.
That was it! :P
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 06, 2018, 04:56:09 am
I've adopted taleden's better "world map" size determination algorithm.
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 08, 2018, 08:40:49 am
Would it be possible to include neighboring races in the finder, i.e. "Elves/Humans/Goblins/Tower: NA/War/Yes/No", or is that information not easily available during the search?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 08, 2018, 02:51:07 pm
Would it be possible to include neighboring races in the finder, i.e. "Elves/Humans/Goblins/Tower: NA/War/Yes/No", or is that information not easily available during the search?
It's possible, but not trivial. It would require its own search pass (although it would have to run only once and it's a world tile level search), because it depends on distances from civs, which means both figuring out what the distances are, and checking for impassable terrain (including the passability resulting from a player fortress [and I don't know if other pass-through sites can be placed on "impassable" tiles apart from probably dwarven fortresses on mountains, and I'm not completely sure what sites ARE pass-through]). If I was to do it, I'd probably implement a fairly crummy flood fill check for each site of each civ, which wouldn't be particularly efficient. Another issue is that I don't know how DF decides which civ gets to represent each race, which would be required to implement a relations check (presumably war is determined by the mother civ being at war with them [which ties into the dwarven civ selection], but the logic would still have to determine if that civ is considered the closest one).

Thus, there are known unknowns that would have to be investigated before an implementation can be made to hit the unknown unknowns.
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 09, 2018, 11:22:59 am
Hm, ok. Pity there's no easy dfhack memory structure you could just pull it from while scanning over the world during the main search; it *seems* like it ought to be in there somewhere since the game can already display neighbors information, but maybe it only calculates and populates those structures if the user has actually TABbed to the Neighbors display. Oh well, just a thought.

Meanwhile, do you have any interest in making some adjustments to make embark-assistant more suitable for general use, to maybe get it enabled by default in future DFHack releases a-la manipulator? It's a great tool and I think a lot of people would appreciate it who currently don't even know it exists, but it'd be more work for you initially to make it work better as an always-on thing, and probably more work ongoing with all the newcomers asking for features. :)

If you're interested then I'm happy to help with the interface design considerations, or I could try implementing the changes myself if you'd like (is the source code available somewhere?).
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 09, 2018, 03:16:16 pm
Given how DF generally works, I'd expect DF to generate neighbor info on the fly based on which world tile and civ you've currently selected. Whether that's done when TAB-ing or selecting civ/moving doesn't really matter, I think.

It would probably be a worthwhile addition, but the logic details have to be determined first (i.e. exactly how sites affect pathing), which probably isn't an impossible task with some script investigations. In addition to that, it would have to fit into the UI somehow, i.e. if you're using one line per race you're going to end up with quite a few lines (especially with stuff like Masterworks which, as far as I understand, effectively multiplies the races by some factor, plus introduces new ones), but if that's used a fairly simple N/A, Any Relation, War, Peace, Absent selection would work. A possibility might be a sub menu/page.

The Manipulator is integrated via a key in parallel with the normal UI, which I think is a good way to handle this kind of tools, rather than replacing the vanilla functionality outright. There were a few different reasons I didn't go that route:
- I had no idea how the tool would be received, so an active opt-in seemed like the safer approach.
- I've never integrated anything, so I'd need to find out how to do that (probably not an impossible task).
- It definitely has to be possible to use vanilla without actively disabling it, both because it displays things that might want to be kept hidden, and because its increased screen real estate requirements.

The source code is integrated (as a plugin) into DFHack, so it's available from Github https://github.com/DFHack/dfhack (https://github.com/DFHack/dfhack) (which is a royal pain to deal with, in my view, but that's what you have to deal with unless you want to support development environments for all OS' and bit combinations yourself). Since it's part of DFHack it means anyone (with an account) can submit Pull Requests for changes of it. The reasons for this thread is both as an advertisement of sorts, and a way to direct tool related issues/requests here rather than clutter the main DFHack thread with them.
Title: Re: DFHack plugin embark-assistant
Post by: thefinn on August 17, 2018, 12:54:17 pm
Do I have to wait for the search to complete to find the overlay working?

I'd love it to work even if I cancel the search after the first couple pop up.

Searches are long...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 18, 2018, 03:40:00 am
Searching does indeed take a long time. This is because it scanning a lot of data, plus that this data has to be loaded by DF itself. It can be noted that DF's own searches also take quite some time.

It should be possible to leave the search indications in the state they were when a search was cancelled, but I'd have to investigate what happens if you were to move the focus to world tiles that have not yet been searched. I suspect additional logic would be needed, and I wouldn't be surprised if you could get incorrect indications in such areas because they were based on data that hadn't actually been produced, in particular if the very first search is aborted.
Title: Re: DFHack plugin embark-assistant
Post by: thefinn on August 18, 2018, 01:24:22 pm
Searching does indeed take a long time. This is because it scanning a lot of data, plus that this data has to be loaded by DF itself. It can be noted that DF's own searches also take quite some time.

It should be possible to leave the search indications in the state they were when a search was cancelled, but I'd have to investigate what happens if you were to move the focus to world tiles that have not yet been searched. I suspect additional logic would be needed, and I wouldn't be surprised if you could get incorrect indications in such areas because they were based on data that hadn't actually been produced, in particular if the very first search is aborted.

Yeah I'm not too sure what I'm doing wrong. Clearly something substantial and probably quite basic. But even when leaving the search to go through to the end... I get nothing but a total of tiles that meet the requirements I set.

I'm using windowed mode, not sure if that makes a difference. I see some X's crop up when it's in the search but only in the region window - not the world or local windows. Very odd.

*shrug*
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 18, 2018, 04:13:32 pm
There are currently no indicators in the "World" section, only in the "Region" and "Local" ones. I've added the code needed to cover the "World" section as well, but it won't appear before the next DFHack release (provided the Pull Request is accepted). I've also changed to code to allow a 'f'ind to be 'c'ancelled while leaving the indicators for what has been found so far, but, again, it has to be accepted and released to have any end user effect.

Windowed mode or not should make no difference (I'm using windowed mode, and I don't think I've even tested it in full screen mode). It can be noted that the DF focus jumps around to look at the area at the focus during the search, and this is visible on the "Local" and "Region" sections, but if you have a large map (which I assume you have since searching takes a long time) the "Region" section shows only a portion of the world, and that portion may not cover any matches, so you'd have to scroll around to find the matches, in particular if the matching tile count is low, as that probably means they're far apart (or gathered in a cluster somewhere). Unless the "Local" window happens to show a world tile where you've got a match you won't see any matches, and, again, if the matches are few the chance of happening upon a matching world tile is slim.
Title: Re: DFHack plugin embark-assistant
Post by: thefinn on August 18, 2018, 05:10:21 pm
Gotcha I will give it another go then.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 19, 2018, 02:41:42 am
Gotcha I will give it another go then.
Another thing to try is to search for something that's very common, such a e.g. just the presence of a river in the form of a brook or larger. That should match most of the tiles, and thus should make it easy to see if (and how) it works in general. If you do that on a small world it doesn't take a long time...
Title: Re: DFHack plugin embark-assistant
Post by: taleden on August 31, 2018, 01:38:18 pm
PatrikLundell, do you by chance have a lua implementation of your process for scanning world tiles and identifying the soil layers present (even if it's super slow)?

I'm trying to gather some data on how soil, sand and clay generate, so what I'm hoping to do is run a script that can scan through every distinct biome in a world (or, if necessary, every world/region/local/whateveritscalled tile), generate a string describing the pattern of soil layers observed there, and report at the end all the distinct patterns that were found in the world. So if you happen to have that scanning logic already written in lua, it'd be easy for me to hack on some extra record keeping for what I'm trying to do, even if it takes forever to run compared to the C version.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 31, 2018, 04:22:21 pm
I have the Lua script prototype for the Embark Assistant. There are bugs in it, of course, as I expected it to be too slow to be useful, but most of the basic logic is in there, and I don't think there are any bugs in the geo biome scannings themselves (yes, there are several versions of it, as the overall logic was needed in several places. I tried caching data, but the estimate indicated far too many gigabytes to be reasonable, so data is discarded and regenerated, which is what DF do a lot as well). However, I have copied the logic from Prospector, including some stuff involving an unnamed field and ocean biomes... I've estimated the time to scan a full size world using the script to be around 30 minutes.
https://www.dropbox.com/s/sfstaxr2yq1irvk/embark_assistant.lua?dl=0 (https://www.dropbox.com/s/sfstaxr2yq1irvk/embark_assistant.lua?dl=0) AS IS, PROTOTYPE, NO SUPPORT. Not for actual use.

However, the Prospector logic takes soil erosion and SMR cutoff into consideration, and so has to be run for each tile rather than per biome. If you're just after how the geo biomes are constructed the Biome Manipulator is probably a better source http://www.bay12forums.com/smf/index.php?topic=164658.0 (http://www.bay12forums.com/smf/index.php?topic=164658.0).
Title: Re: DFHack plugin embark-assistant
Post by: Burneddi on December 02, 2018, 07:03:58 pm
Can you add an option that searches for underground fuel, ie. lignite or bituminous coal (or both)?

Also a wish from Keupo's stream: being able to search for surroundings that are husking but not reanimating.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 03, 2018, 03:36:20 am
Fuel: I have to look at it before answering, as such a functionality would require means to figure out how to determine if a mineral can be used as fuel (as the logic shouldn't be dependent on what's in the vanilla raw set).

Husking: Sounds like it should be possible, although I think it would require some restructuring of the evil biome search criteria.
Title: Re: DFHack plugin embark-assistant
Post by: mifki on December 03, 2018, 05:45:58 am
Fuel: I have to look at it before answering, as such a functionality would require means to figure out how to determine if a mineral can be used as fuel (as the logic shouldn't be dependent on what's in the vanilla raw set).

Coke itself as fuel is hardcoded, then you need to find all reactions that produce it and see what their reagents are. Of course theoretically you can have complex reactions with multiple reagents or reaction chains instead of the default ones, but I think some simplified checks are enough.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 03, 2018, 07:25:35 am
Thanks mifki. That's the same conclusion I came to when I started to look at it. I wrote a script to test it out, and that seemed to work out correctly.

Spoiler (click to show/hide)
Title: Re: DFHack plugin embark-assistant
Post by: Burneddi on December 03, 2018, 09:01:00 am
An alternative solution to the fuel thing would be the ability to select multiple items at once in each category of economic stone (and why not other stones too), and when this is done the search criteria will be that at least one of them is present. This could be a fair bit more difficult to implement depending on how the search is implemented though, I wager.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on December 03, 2018, 12:54:00 pm
haven't tried, but can you add "trees" and "other vegetation" with many different values aswell?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 03, 2018, 01:33:13 pm
An alternative solution to the fuel thing would be the ability to select multiple items at once in each category of economic stone (and why not other stones too), and when this is done the search criteria will be that at least one of them is present. This could be a fair bit more difficult to implement depending on how the search is implemented though, I wager.
Instead of searching for a particular value, each geo biome element would have to be matched against a list, which should be about the same cost as matching another element (i.e. a list of two alternatives would cost about the same as two separate mandatory ones). The trickier part to implement that would probably be to change the list logic to allow for multiple selections while still being usable, somehow (as usual: it's typically the UI that causes the most trouble. For instance, the UI can't show what's selected, as there's room for only a single entry, so it might have to show something like "<Multiple alternatives selected>" instead.).

haven't tried, but can you add "trees" and "other vegetation" with many different values aswell?
I don't understand the question...
The various biomes you can search for imply various levels of starting trees (with exception of deserts, which can be completely treeless if the rainfall is low enough, and only have starting trees but won't get saplings if it's marginally higher). All biomes that aren't completely treeless or extremely low rainfall deserts get completely junglified given enough time [and no logging, of course] (which varies based on the biome).

If you mean "I want to have Feather Trees, Kobold Bulb, and Sliver Barb", that's doable (with very long lists of plants to select from), but I don't think it would be particularly useful: it would probably be better to look for the appropriate biomes/evilness and use the Biome Manipulator script to hack the ones that DF excluded from their biomes into the embark biomes instead.
I'm not sure how to implement it in a fashion that's not too costly either: possibly pre processing of biomes to list the ones containing the up to 3 selected plants: iterating over all the plants of a biome (as well as verifying the world tile is of an appropriate type is definitely too costly.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on December 03, 2018, 02:22:15 pm
it's just that in the vanilla site finder you cannot select anything about trees at all.
so in certain worlds, i would look for a site with no trees and certain other properties in vein, but the sitefinder cannot help much with it yet.
in others i want a steep mountainside next to a dense jungle and look at 100 sites just to find that there is no place on the whole map, but a sitefinder with trees min/max would be a great help with that.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 03, 2018, 06:06:21 pm
it's just that in the vanilla site finder you cannot select anything about trees at all.
so in certain worlds, i would look for a site with no trees and certain other properties in vein, but the sitefinder cannot help much with it yet.
in others i want a steep mountainside next to a dense jungle and look at 100 sites just to find that there is no place on the whole map, but a sitefinder with trees min/max would be a great help with that.
As I said, biomes imply their general tree densities and the plugin also provides region type as a search criterion. This means that mountain present (doesn't matter if you select biome or region type, as there's a 1:1 mapping for this one) + region type "jungle" present would find you every place where forest (of any kind, as that is what "jungle" actually maps to) is present together with mountain within an embark (while also matching the other criteria, of course).

Edit:
@Burneddi: Looking at the code, I find that it already supports searching for the reanimation option requested (and it's listed on the first page as well, which means it should be available [i.e. not awaiting a new DFHack release]): As far as I know, thralling and husking are the same thing.
N/A, Both, Any, Thralling, Reanimation, Not_Thralling, None
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on December 04, 2018, 10:14:08 am
ah, then i must've forgot about that once i reached the end of the long list of awesome features :) sorry for having wasted your and my time.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 28, 2018, 04:20:49 am
DFHack 0.44.12-r2 has been released, which means a number of changes made to the Embark Assistant are available:
- Match indicators are now available on top of the "World" map.
- Changed the 'c'ancel logic to halt a search partway through if active and clear the results if not, allowing for partial results.
- Added Coal as a search criterion, as well as an added embark selection indication.
Title: Re: DFHack plugin embark-assistant
Post by: Schmaven on April 13, 2019, 07:27:03 pm
Just posting to say thank you for making a great embark finder!  I just now found a suitably difficult embark - not too hard, not too easy.  Well, 6 of the 7 dwarves are dead and it's only part way through the 2nd month, so it might be too hard, but that's what reclaiming is for  8)

I have iron, flux, evil clouds, high savagery, part evil, part neutral, cold weather, mountains, a stream and only a partial aquifer!

The search seemed to take about the same or less time than the vanilla search function too.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on April 14, 2019, 04:17:46 am
can you add search token for nonspecific searches?

"any fuel" to have at least one of the both coke producing lignite or bitumous coal
or just add new point "fuel" with options "N/A, absent, present, lignite, bitumous coal, both"

trees: none, little, moderate, woodland (i know i can set the search for certain biomes, but if i seriously don't care for the biome, but only for at least a few trees, that doesn't help)

keep up the great work on this neat plugin :)
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on April 14, 2019, 08:00:22 am
- I don't understand what a non specific search is... String matching across unspecified categories doesn't really work without at least specifying which categories to search.

- "Coal" (as introduced two posts up) is any of the ores that produce coke. Is there any reason to specify which one (and I don't want to list them individually, as the code is intended to work even if you add new versions of such ores, so the code looks for the reaction to produce coke)? After all, if you're interested in bitcoal specifically you can search for that mineral.

- Trees: I'm not aware of the specific details that result in various amounts of trees at embark (all embarks that support saplings will reach the same junglified end state eventually in the absence of cutting, while the time it takes varies). I know that if the rainfall is extremely small there are no trees at all, and at a marginally higher level trees may be present at embark, but no saplings will appear (I don't remember the details, but it's something like 0-1: no trees, <5 no saplings, and the first category doesn't get shrubs either [but still supports farming of biome compatible crops]). Beyond that I have no info on what results in which initial tree density (well, ocean, lake, glacier, and mountain do not support trees at all). I can make (somewhat educated) guesses about which biomes ought to have which initial tree densities, but I don't know if there are any other factors that affects the outcome (although I suspect there are factors that could cause e.g. a savanna to be either sparse or moderate). DF obviously knows the differences as it's presented pre embark, but I don't know the formulae beyond what's mentioned.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on April 14, 2019, 02:05:46 pm
i wasnt aware you added general "coke yes/no".
what i meant was that sometimes i want an embar without trees or at least don't care if there are trees and other times i just want trees, because i'll need them, while not caring if it's jungle, savannah, swamp or woodland hills.
so being able to sort and have trees or know that there won't be any would be useful, but i see how that is difficult to do when the game gives not enough info.
i even once had embarked in an area with trees:woodland and not even one tree was present.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on May 25, 2019, 11:28:32 am
after the "mousequery edge" bug on 44.12 is resolved, i tried it out, loved the way it is now, but the game is still too prone to crashing.
so, could you make a version with the new features, but for 0.44.09-r1 ?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 25, 2019, 11:50:41 am
No. The plugin is a part of DFHack, and so would require a new DFHack release for 0.44.09, which you'd have to convince those responsible for that to do, as I have no authority over that (and I think that would either require a significant monetary incentive or a physical threat: I can accept the former but won't condone the latter).
The reliance of being coded into DFHack releases is an important reason I avoid plugins whenever possible and make scripts instead (the other main reason is Git), but the performance hit from using a script is just too large in this case (estimated search time for a max size world is about ½ hour based on my script prototype [which isn't in a usable state]).

It would be possible for you to make your own copy of the desired DFHack version on Github/your computer, perform whatever adjustments are needed, compile it, and use the hacked DFHack version with your DF instance. Obviously, it requires that you know a bit about coding in C(++), the DFHack mapped structures, and are willing to fight Git.

Personally I've quit DF until the raid crash bug(s) have been fixed and the Villains are somewhat stable. My current estimate is that this would happen around September.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on May 25, 2019, 12:01:55 pm
i totally understand you. i doubt they'll dive back into 44.09 though.
for now the 44.09 version works stable and your function does a great job already. thanks again for this great plugin :)
Title: Re: DFHack plugin embark-assistant
Post by: DerMeister on May 25, 2019, 12:48:52 pm
I need plugin for embark directly on underworld spire.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on May 25, 2019, 12:52:34 pm
I need plugin for embark directly on underworld spire.
just edit d_init to show stuff not on "FINDER" but on "ALWAYS"
then, if it is present, you'll see stuff on embark map
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on May 25, 2019, 04:59:25 pm
It's not impossible to put together a DFHack release for an old build of DF. We've considered that before, but only for major versions (e.g. 0.34.11) and have never actually done it. It'd be a bit annoying to test, since saves aren't forward-compatible.
after the "mousequery edge" bug on 44.12 is resolved, i tried it out, loved the way it is now, but the game is still too prone to crashing.
so, could you make a version with the new features, but for 0.44.09-r1 ?
From this, it sounds like both versions are unstable for you, so I'm not seeing a clear reason to make a build for 0.44.09. Let me know if I'm misunderstanding. I also haven't seen a clear consensus on 0.44.09 being more stable than 0.44.12 (and why .09 and not .11?), but maybe I missed something.

For comparison: the weapon trap crash of 0.43.05 was something widespread enough that we would have considered supporting 0.43.04 too. However, that was infeasible due to the 64-bit changes in 0.43.05.
I feel like there was some longstanding bug in 0.34.11 too, but DFHack for 0.34.11 also supported 0.34.10 anyway since they were binary-compatible.

I need plugin for embark directly on underworld spire.
Not totally sure what the issue is here, but two options:
- If you can't see the spires, see Pvt Pirate's suggestion.
- If you can see the spires but can't embark on them, try "embark-tools enable anywhere".
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 25, 2019, 05:37:00 pm
While it's not impossible to make DFHack versions based on older DF versions, it's bound to be a fair bit of work, and thus would require a fairly significant incentive to do.

@DerMeister: It's a bit hard to understand what you want, so I'm guessing wildly:
It's not possible for a spire to reach the surface as far as I've seen (it was a long time ago, according to what I've heard), nor is it possible to embark underground. The Embark Assistant does not hack anything, but presents info about the world as it is. It is possible to hack various things using DFHack, though:
- Spires can be changed to reach any cavern level, as well as to stay the magma sea.
- Spires can be moved within their 2*2 mid level tile grids so they appear on a different mid level tile.
- The surface can be hacked to be lowered so much that one or more caverns are exposed, which can enable embarking at the cavern. This can also lead to cave-ins as cavern floors hacked to not exist result in material falling as soon as you embark.
These things can be done using the Region Manipulator script http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345 (http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345).
It may be possible to add new spires, but I haven't tried to do that, so such an attempt would have to be performed "manually".
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on May 26, 2019, 06:38:19 am
It's not impossible to put together a DFHack release for an old build of DF. We've considered that before, but only for major versions (e.g. 0.34.11) and have never actually done it. It'd be a bit annoying to test, since saves aren't forward-compatible.
after the "mousequery edge" bug on 44.12 is resolved, i tried it out, loved the way it is now, but the game is still too prone to crashing.
so, could you make a version with the new features, but for 0.44.09-r1 ?
From this, it sounds like both versions are unstable for you, so I'm not seeing a clear reason to make a build for 0.44.09. Let me know if I'm misunderstanding. I also haven't seen a clear consensus on 0.44.09 being more stable than 0.44.12 (and why .09 and not .11?), but maybe I missed something.

For comparison: the weapon trap crash of 0.43.05 was something widespread enough that we would have considered supporting 0.43.04 too. However, that was infeasible due to the 64-bit changes in 0.43.05.
I feel like there was some longstanding bug in 0.34.11 too, but DFHack for 0.34.11 also supported 0.34.10 anyway since they were binary-compatible.
well, the 44.09-r1 is stable for me and the mousequery bug was fixable by using a different fork of dfhack or twbt (i don't remember right now). i can't find the necessary files online anywhere, which is why i repacked that fixed/patched version as a backup for myself.
the (now fixed) mousequery bug in 44.12 kept me from playing it at all, so i never came into any crashes, because i never played long enough.
i absolutely understand your considerations which versions to support, especially since it can be quite the work involved.

EDIT: i just found out, that even when only one embark square is marked, when i move the 3x3 embark so the flashing one is in the center, all biomes show the requirements as being met.
i always searched for ages to find a 3x3 flashing square. was i dumb before or is this not how it works?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 31, 2019, 11:33:56 am
Have you read the help screens? Unless I've made a grave mistake, it should state that a match for the embark rectangle is indicated by the single tile up in the top left corner or the rectangle, with the other tiles in the rectangle indicating the rectangles with those tiles as their corners.
The reason for this is that there is a need to indicate a match for any kind of rectangle, with a clear indication of where the matching rectangle is. You'd also note that with a 3*3 rectangle the two lowest  rows and the two rightmost columns never show any matches (because that would indicate a match in non existent mid level tiles outside the area).

Note that there are search conditions that require multiple embark tiles with different conditions in different tiles, such as e.g. partial aquifers, so a "matching tiles" logic doesn't work.
Title: Re: DFHack plugin embark-assistant
Post by: clinodev on May 31, 2019, 04:52:25 pm
Have you read the help screens? Unless I've made a grave mistake, it should state that a match for the embark rectangle is indicated by the single tile up in the top left corner or the rectangle, with the other tiles in the rectangle indicating the rectangles with those tiles as their corners.

Well, heck. Today I learned.

That's going to make finding great embark sites even easier!
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on May 31, 2019, 06:23:05 pm
Have you read the help screens? Unless I've made a grave mistake, it should state that a match for the embark rectangle is indicated by the single tile up in the top left corner or the rectangle, with the other tiles in the rectangle indicating the rectangles with those tiles as their corners.
The reason for this is that there is a need to indicate a match for any kind of rectangle, with a clear indication of where the matching rectangle is. You'd also note that with a 3*3 rectangle the two lowest  rows and the two rightmost columns never show any matches (because that would indicate a match in non existent mid level tiles outside the area).

Note that there are search conditions that require multiple embark tiles with different conditions in different tiles, such as e.g. partial aquifers, so a "matching tiles" logic doesn't work.
so i'd have ti place the 3x3 with its top-left tile on the flashing tile?
i mean i search for 3x3 embarks and there are sometimes 1x1 tiles flashing. maybe we just use different terminology...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 01, 2019, 02:58:59 am
yeS. as I believe I said, the tile in the top left corner indicates the match/no match for the embark rectangle of the selected size with its top left corner on that tilE.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on June 01, 2019, 03:01:22 am
oh, then i actually was bad at reading...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 06, 2019, 04:41:40 pm
vjek encountered a crash bug when the advanced world gen parameters specified that no metals should be generated procedurally. The issue can be worked around by specifying at least one metal.

A pull request with a correction has been made, but there probably won't be any more DFHack releases before the Villains changes have been released.
Title: Re: DFHack plugin embark-assistant
Post by: clinodev on June 06, 2019, 06:51:48 pm

Interesting. I wonder what other factors are involved?

I ask because my regular AWG parameter set specifies "[GENERATE_DIVINE_MATERIALS:0]", and in the process of finding a world I liked for a tutorial I recently generated literally (in the old fashioned sense of "I'm not exaggerating for effect,") dozens of worlds over the course of three nights and ran embark-assistant on them, with no crashes that I recall.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 07, 2019, 03:49:13 am
Thanks for the follow up, clinodev.

Since your experience didn't seem to make sense given what the code looks (or looked) like, I ran a script that printed the names of all generated materials in my last fortress. It turns out that beside DIVINE_X, there's also EVIL_RAIN_X, so apparently you'd have to disable both evil weather and divine materials to be affected by the bug (I'm not sure if evil mist would appear as well: that world has those set to 0).

I think setting divine materials to 1 is better than setting the number of evil weathers to one though, if you really don't want either.
Title: Re: DFHack plugin embark-assistant
Post by: clinodev on June 07, 2019, 04:41:43 am
Ah, nice.

Yes, I've always controlled my evil weather exposure through site selection, but annoying procgen materials clutter my menus and caravans no matter how far I embark away from their sources.
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on June 14, 2019, 10:07:35 am
after the "mousequery edge" bug on 44.12 is resolved, i tried it out, loved the way it is now, but the game is still too prone to crashing.
so, could you make a version with the new features, but for 0.44.09-r1 ?
Two notes:

One, you can port 44.09 saves to 44.12. So you can copy your region folder to 44.12, and look for embark there, then quit and start the embark in 44.09. Iirc geography was also the same between the two, so generating from same parameters+seed might work as well for this.


Second, what you ask, if you're still interested, is not quite the same as doing latest dfhack release for an old build of DF, and the ways it differs is that it is a lot easier.
I'm guessing you would need to 1) compile dfhack for your OS according to dfhack build instructions, expect instead of pulling the most recent dfhack from git pulling the latest 44.09 version; 2) replace the embark-assistant plugin code with the latest one; 3) compare the plugin codes and unreplace any anonymous/unknown fields that got named with their 44.09 versions.

(I once did something like that for TWBT here (http://www.bay12forums.com/smf/index.php?topic=138754.msg7808729#msg7808729), though that was likely far more involved due both 32-64 bit jump and Next being substantial jump.)
Title: Re: DFHack plugin embark-assistant
Post by: vjek on June 19, 2019, 09:18:43 am
Some feature requests for this amazing, time saving tool..
If the above it not possible:
And some very specific things, because some embarks you just want a particular way..
Not sure if this is possible, pre-embark:

Thanks again, you've saved me hundreds of hours at least, so far.  The save/load feature, in particular, is just.. a thing of beauty.  :o 8)
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 19, 2019, 02:40:03 pm
I'm not aware of any problem with finding marble. What's the problem, and what are the symptoms?

Various forms of OR choice selections have been discussed before. The issue is primarily a UI one, i.e. how to design the interface such that you can define lists without getting an cluttered mess with no overview.

It's technically possible to determine only if the "dominant" biome of a mid level tile matches that of the other tiles of the embark, as I'm not aware of any way to know if the biome of any surrounding tiles will be present on the tile or not. Thus, to absolutely ensure an embark is perfectly flat, you need to ensure an a rectangle one tile larger in all directions (i.e 3*4 -> 5*7) has all tiles of the same elevation. That also would exclude all embarks hugging the border of the world tile. I usually perform this check manually using the vanilla DF elevation difference display to select an embark tile that has a proper surrounding.

It IS possible to determine if caverns have the Underground or Chasm (i.e. "muddy cavern") biome, but as far as I know the things controlling whether a lake is present or not in a "normal" cavern is determined by a "water" parameter that provides a coverage percentage to be used by the RNG (the "water" parameter is, in turned, generated from the range defined by a world gen parameter pair, available via advanced world gen: I set my caverns to have 0-20% coverage, if I remember correctly, and this means most caverns don't have water, and muddy ones are common).

The cavern biomes seem to work the same as the surface ones, i.e. there's a chance legal things are available or not, which is available in the subsurface region data. Thus, I don't think it would be a technical problem to perform a match check (although the two cavern biomes are currently so boring the tool doesn't look at it), but a UI design one.

The Save/Load feature was implemented as a result of a suggestion/request, by the way.
Title: Re: DFHack plugin embark-assistant
Post by: vjek on June 19, 2019, 03:43:41 pm
In most worlds I generate, if the vanilla DF embark screen says flux, there's no flux.
In the cases where that's true, embark-assistant will say there's Marble as the source of flux.  There's no marble.  In the past week alone, I've seen dozens of examples of this, to the point where I don't even count marble as valid, and just skip those worlds where only marbe is found as flux, because it's not actually there.

I have a sample world, and embark, for just such a bug hunt.. (but I can find/gen as many as you want, it's that consistent)
Spoiler (click to show/hide)
The entire south half of the world has the marble-no-marble issue, while a few in the north do as well.
It's not the entire world, though.  Some embarks around the human/NW area that claim to have flux/marble actually do, but the overwhelming majority of embarks in this world don't.
I don't think this is an embark-assistant problem, though, which is why I was asking for a feature request in the way I did, as I suspect this is a DF issue, and embark-assistant is simply passing on what it thinks is valid information. 
In particular, those highlighted embarks in the embark areas above, they all say "Flux stone layer" present, but... there's not, of any kind.  Even without embark-assistant, it's not working as intended, from what I can see.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 19, 2019, 05:34:31 pm
Thanks for the info, vjek. I suspect it's true it's some kind of DF issue, but it's one I haven't heard about, so I think it needs an investigation to figure out what it is.

One possibility would be the known DF issue of the magma sea cutting off the geo biome above the layer of interest (marble/iron/...) layer, and some bug in the Embark Assistant's handling of that bug/deficiency. However this is just a guess until I've had time to try to figure out what's going on.
Title: Re: DFHack plugin embark-assistant
Post by: vjek on June 20, 2019, 12:37:31 am
I agree.  I think it's related to a single cavern, as well.  Almost all of my worlds only have a single cavern. (instead of the default 3)

I've seen quite a few worlds (with the same adv. worldgen parameters) where there are places that have marble, and only a single layer is visible above the SMR sea, or within the magma sea.  Next to it, or in the next world tile, an adjacent biome won't have any flux/marble, but claim there is some.
In particular, those places tend to be where an uneven embark or different biome crosses, intersects, or abuts.  Under those conditions, with a single cavern, it will often say there is flux/marble but there is none.

I guess it could be as simple as:  The SMR sea is where the marble technically is (or would be, if there were 2 or 3 caverns), but you can't use it or see it, because.. it's the SMR sea.  This might be the conditions required to duplicate the issue?
As a workaround, (an additional option) would it be possible to have embark-assistant, under the Flux menu, find all non-marble flux?  ( N/A, Present, Absent, Non-Marble )
I've never seen Dolomite, Calcite, Limestone, or Chalk show up (or not) in this same way.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 20, 2019, 08:42:39 am
I've found the cause of the bug. The logic taken from Prospector somehow missed a crucial line. I'm a bit puzzled, as I'm fairly sure I've tested that the transferred logic worked, so maybe some later change did remove it by mistake.  Regardless of the cause, however, adding/restoring the line caused the logic to work as intended (i.e. not report things [metals, minerals, ...] below the cutoff as present). This means 33 world tiles with flux in your world, rather than most of them.

I'm in the process of creating a pull request for this bug fix, but don't expect a new DFHack to be produced until a fair while after the Villains release (I expect it will take time to map/verify the DFHack mapping of DF structures, as usual).
Title: Re: DFHack plugin embark-assistant
Post by: vjek on June 20, 2019, 10:49:41 am
Well look at you being my worldgen hero for the day.  8)  Nice bug hunting!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 08, 2019, 10:14:23 am
I've done some DFHack structure exploration, and think I've finally gotten a handle on how the mid level tile "edges" work, i.e. how the biome of tiles flow into adjacent ones. In practical terms, that means it may be possible to actually determine if a mid level tile will get small pieces of different biomes, but there are significant caveats when it comes to actually using that info.

How (I think) it works [Technical, can be skipped]:
- For each mid level tile side, information exists whether the main biome of the tile should be used, or if the neighboring tile's one should be used, i.e. if biomes should flow in or out. In most cases it doesn't matter, as it's the same on both sides, but the code has to handle the situation.
- Similarly, for each corner there's info on which of the 4 tiles that meet there that should be used to provide the corner information for the corresponding corner of all of the 4 tiles.
- There's info on how the sides of a tile is split into one side section and 2 corner section (the corners need their other side's info to be completely defined).
- The split of sides into sections for a starting point for DF's (RNG seed driven) algorithm for fighting it out between the "intruder" and "defending" biome, as well as between different "intruders". This can result in the boundary between sections ending up in different places from the one defined, and it can also have the "intruder" pushed back completely along part of the line. This means the "foreign" biomes can vary much in size, with no external info on how large they'll be.
- I GUESS an "intruder" biome can only be pushed back to the border, but not spilled over backwards (i.e. that the intrusion direction will always hold, so you can reliably predict that no foreign biome will appear along a section).
- I furthermore GUESS that is should be possible, although probably extremely rare, that an "intruder" biome is completely expelled, resulting in no foreign tile where the initial info stated there should be one. If it happened, there would be a completely straight border line for that section, assuming the previous guess holds.
- The term "biome" isn't completely accurate, as apart from the biome and geo biome, the information also covers Elevation, which DF defined on a mid level tile level, and so can vary even if the actual biome is the same.

Complications:
- The mid level tiles at the border of each world tile would need to potentially import information from mid level tiles belonging to another world tile. While this isn't a problem after embark, it is pre embark, because then this information exists only for a single world tiles at that time (3*3 world tiles post embark). This is a rather significant issue, because taking all information into consideration would require either a very significant cashing of information bloating the memory footprint, or scanning the world twice on the first search (the relevant border information can probably be cashed during the first scan, as it shouldn't be too much data), because regardless of which order you scan the world in, world tiles bordering the unscanned tiles rely on information that DF hasn't generated yet for those tiles. A compromise of sorts is to not consider the border tiles for embarks during the first scan.
- When do we want to take "foreign" biome incursions into mid level tiles into consideration? That's actually not a straight forward issue: For getting a flat embark we definitely want to take it into account, but if you're looking for iron, you won't be very happy to find the "iron" consists of a dozen in-game tiles of the geo biome, and they may not even have any vein in it...

- Savagery/Evilness parameters: Most of the time you probably want incursions to be taken into account.
- Aquifer: You probably want to take it into account all the time.
- Flat: All the time.
- Clay and Sand only need a single tile to access the resource, but incursions tend to be (dangerously) close to the border, but all the time would probably be good enough.
- Coal/Flux: Incursions should probably be ignored, as you want decent volumes.
- Soil: Don't know...
- Evil/Syndrome rain/reanimation: Probably situation dependent...
- Min/Max Biome count, region type, biome: You'd probably want to take incursions into account, but will be unhappy if you were aiming for something that isn't present in that small section...
- Metal/Economic/Mineral: Same as Coal/Flux: Incursions are typically too small to be of interest.

Note that adding switches for whether to take incursions into consideration on a selection item per selection item basis would result in a selection list bloat which would make the UI unwieldier than necessary.
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on July 08, 2019, 11:01:17 am
Regarding checking for iron, it's probably unnecessary to say but JSYK veins/clusters/blobs will always depend on the 'main' geo biome of the 48x48 tile square they sit in. As far as I've seen, it is not possible to have a tile of aluminium and blob of magnetite share that block. Coals, same story.

As for flux, incursions can contain significant amount of it; ex over 2k in my 1x1 - because its height is 7 z-levels. Then again, it depends on what one considers decent; that's not enough to build even half of a proper tower.

Soil, I think you and I will think incursion, and some will be happy with single tree for bootstrapping. Others may want larger area for sustainably forestry.

I'd say partial reanimation is lot like partial aquifers, but that's just me - it's going to be a source of undead wildlife, at least.


The technical part is why the mountain elevation as it descends can look like U-shaped spikes, I assume.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 08, 2019, 11:24:30 am
I didn't know incursions couldn't contain veins.

Incursions CAN contain significant amounts, but they can also contain almost nothing: you could have gotten 50 tiles (12.5 boulders) total instead. Also, if I remember correctly, some kinds of flux come as veins.

It should be noted that according to the DF structure XML file, there are special rules concerning mountains and lakes/oceans: lakes and oceans are supposed to yield to anything else regardless of what the instructions say, and mountains are supposed to yield to everything except lakes and oceans. I.e. land tiles can intrude on lake/ocean/mountain tiles, but they can never intrude on normal tiles.
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on July 08, 2019, 11:42:04 am
Yeah, that's "almost none" amount. Calcite is the flux that comes as vein-type - but it only happens as small clusters within limestone and marble (both layer fluxes), so....Well, I suppose one could mod other flux veins, though I haven't heard of anybody doing so.

Hm. Good to know about l/o/m; it does seem to match my experience.
Title: Re: DFHack plugin embark-assistant
Post by: Telear on August 22, 2019, 06:37:15 am
One feature I'd love to see in added is the option to do 'embark-assistant search' or some such, which would start embark assistant searching using the saved set of desired features and return a count of matching tiles. This would be enormously helpful when I'm building a whole bunch of worlds and looking for the mythical 3x3 with volcano, by a waterfall with flux and iron. (Yes, I know about region manipulator and its ilk, but I'm running very short histories with the idea of regenerating the hits with a longer history, and RM doesn't really help with that).
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 22, 2019, 07:54:53 am
For that purpose I'd probably write a script that just looks for the desired features around the few volcanoes in the world. A Lua script would likely be faster than a search using the compiled plugin because you'd only look a relatively few potential embarks.
A script could speed things up further by checking if there's a river in the same world tile as the volcano, and skip those that don't have any.

Regardless of the approach, however, you'd have the task of starting the save in pre embark mode, run the script/plugin, and then wait for it to complete (which takes time in large worlds). Using the plugin as it stands currently you'd have to load your saved parameters, enter search mode, and start a search, which isn't many additional key presses.
Title: Re: DFHack plugin embark-assistant
Post by: Telear on August 22, 2019, 10:09:41 am
I'm aiming at eliminating the keypresses entirely. With a script that emits the number of matching tiles, I can write an AHK or Mac Automator thing that will:

Code: [Select]
START:dwarfort -gen 99 RANDOM PROFILE
      Launch dfhack
      Open region99
      dfhack-run search-script
      unless result matches 'found 0 tiles' exit
      dfhack-run die
      rm -rf data/save/region1
      run this workflow again

and just leave it running all night. Right now, I don't know how to write that script because I don't know how to spot that embark-assistant stopped running or how to grab the number of matching tiles from the df window (though I suppose running in ASCII mode might make that a bit more tractable - wait until there are no more yellow Xs on the screen and check the matching tile count).
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 23, 2019, 02:42:19 am
- I'm not familiar with either of the script thingies, and guess the code is just a mock up, but region99 doesn't match up with removal of region1 in case it isn't.
- There won't be any yellow 'X' before the plugin has generated any, so you'd need to at least wait sufficiently long for the top level survey to be completed before checking.

I'll think about the issue, but won't promise anything.
Title: Re: DFHack plugin embark-assistant
Post by: Telear on August 24, 2019, 05:45:23 am
Yup. Very much pseudo code. I'm currently mucking with something that just waits for far too long then grabs a screen shot. Leave it running overnight, then skim through the screen grabs in the morning for any hits. Slightly less elegant, but it should work.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on September 14, 2019, 05:52:45 pm
First of all: I really love this plugin!
Having very specific ideas about the ideal embark location (Volcano, aquifier or stream, sand, warm jungle biome, only friendly neighbors, ...) and being unwilling (for now) to use tools like "PerfectWorld" I rely heavily on batch generation of many worlds - my current run has 100 - and then finding the right one among them, which was quite time consuming in the past.
Now using the plugin and being able to save my search criteria it is much faster and also less involved, which allows me to be even more picky about the best spot.

But I'm wondering: How much of the results are getting cached during one "search session" (=> while searching repeatedly for matches in the same world without restarting the game or quitting the plugin)?
Having a 257x257 world and specifying my usual search criteria it takes between 8 and 10 minutes for the search to finish on my system. Repeating the same search takes almost as long.
So I did some science:
Running the above mentioned search the first time the shell outputs the following
Code: [Select]
matcher::find: Preliminarily matching World Tiles: 16307and searching takes 9 minutes, 25 seconds to finish.
Running it the again it outputs
Code: [Select]
matcher::find: Preliminarily matching World Tiles: 10421and takes 9 minutes and 3 seconds.
Adding an additional biome criterion we get
Code: [Select]
matcher::find: Preliminarily matching World Tiles: 1037and only very few world tiles get highlighted with the black "X" on yellow ground.
But the yellow "X" still iterates from the top of the world to the bottom, about a lot of unmarked tiles and it takes 8:35 to finish.
Running this refined search again took 8:35 to finish.
Would it be possible to only check/iterate the "preliminarily matching world tiles" in a refined search? That could speed up the whole process, couldn't it?

I had a look at the code on github, but my c++ is quite rusty, so the following is just me speculating:
If retaining all the tile info for matching in memory after the first complete search would be to costly memory-wise something like a skip list, a multimap or a database like index structure for the most significant region/world tile characteristics (biome types present, waterfalls, volcano ...) could be used for faster exclusion of tiles from the search space before starting the more detailed spatial checks.
This would make repeated/refined searches much faster.
What do you think?
I'm absolutely willing to help with test-cases and testing and design ideas, with some guidance I might even be able to produce some usable code...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 15, 2019, 02:59:45 am
It's largely a matter of which situation you want to optimize for:
a) Minimize the time it takes to search a full set of potentially matching world tiles; or
b) Minimize the time it takes to search a sparse set of potentially matching world tiles.
Now, if the cost to a) of achieving b) is small, it may be worth aiming for b).

My original prototype (written in Lua, although I was fairly certain the script penalty would be too high to be practical) tried cashing everything, but the estimated memory requirement for that would be excessive: I don't remember the number, but something like 30 GB, which I also suspected would be the case. Therefore I changed to use the philosophy Toady uses, i.e. regenerate information rather than cashing all of it. The plugin stores all the world tile level information used plus some aggregate level info about mid level tiles, but not the mid level tile information itself. The mid level tile aggregate information is generated during the first search, and thus is available for the following searches.

The aggregate level information is of the type "no sand on any tile", which means a search for sand in an embark will skip this world tile when that field is true. Before the first pass this field is false, because we haven't scanned the mid level tiles yet. Similarly, if there's no river in a world tile, there's no waterfall either. In the same vein, this info contains the biomes of the current world tile as well as the surrounding 8 tiles, and if an embark requires a particular biome not on that list the world tile can be skipped (and this list is cut further if examination of the mid level tiles shows that some of those potential biomes are not present). In fact, the yellow X indicates that the tile has to be examined more closely exactly because the top level info collected does not rule out a match.

One complication is that DF uses a data structure with "feature shells", i.e. 16*16 world tile blocks, and loading those take a significant amount of time (about half of the total search time), which has caused me to ensure the world is processed one feature shell at a time. In addition to this, movement from tile to tile is done simulating single world tile movement key input, as I don't know of any other way to get DF to load the feature shells. It is possible to use the 10 tile movement key inputs instead to speed things up, as well as diagonal movement when the preliminary match set is sparse, but that adds (a possibly negligible) overhead to the case where you have to scan more or less every tile. Also of importance is that the movement pattern is complicated enough as it is (it took me a fair while to get it to work correctly). This doesn't rule out that it might be possible to use the current pattern for the first scan and one that tries to cut the number of number of steps down for subsequent searches when all the base data has been collected, though.

A further complication is that the next version of the plugin takes "incursions" into consideration, i.e. bits of neighboring mid level tiles' biomes jutting into embarks, which would allow you to find a single tile embark with 9 biomes on it (assuming one existed in the world, which is highly unlikely). That logic, however, requires info from neighboring world tiles in all directions to find matching embarks at the edges of world tiles, but all the required background info is still collected on the first search, so a different search logic for subsequent searches would still be possible.
Title: Re: DFHack plugin embark-assistant
Post by: DerMeister on September 15, 2019, 04:53:48 am
This plugin add ability to see buildings if I embark on site?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 15, 2019, 07:02:42 am
This plugin add ability to see buildings if I embark on site?
Yes or no, depending on what you mean...

The smallest overlay allows you to see the presence of sites (caves, shrines, etc.) but not the buildings within those sites (display of caves can be enabled by advanced world gen, but the others are not displayed by DF). Thus, if you want to embark on a vault with the aim of digging down to it you can, but the search function does not provide any option to search for them: you're restricted to scour world tiles visually.
The easiest way to find a kind of site you're looking for is probably to write a script that identifies the world tiles where those are, and then use Embark Assistant to see where within that world tile the site is. The main purpose of the display is rather the opposite, i.e. avoiding accidentally embarking on a feature you don't want to mess with.
Title: Re: DFHack plugin embark-assistant
Post by: DerMeister on September 15, 2019, 02:16:30 pm
This plugin add ability to see buildings if I embark on site?
Yes or no, depending on what you mean...

The smallest overlay allows you to see the presence of sites (caves, shrines, etc.) but not the buildings within those sites (display of caves can be enabled by advanced world gen, but the others are not displayed by DF). Thus, if you want to embark on a vault with the aim of digging down to it you can, but the search function does not provide any option to search for them: you're restricted to scour world tiles visually.
The easiest way to find a kind of site you're looking for is probably to write a script that identifies the world tiles where those are, and then use Embark Assistant to see where within that world tile the site is. The main purpose of the display is rather the opposite, i.e. avoiding accidentally embarking on a feature you don't want to mess with.
I just want embark directly on underwold spire.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 15, 2019, 02:39:11 pm
Candy spires are not sites, and thus not shown on the embark overlay. However, the plugin allows you to search for embarks with a given minimum number of spires, and the results will match only such sites.
There are 64 spires in each world tile, and they're randomly distributed within 2*2 mid level tile blocks aligned with the edges. Thus, a 2*2 embark flush to any corner will have exactly one spire, which randomly appears in one of the mid level tiles. If you're not aligned with the 2*2 grid the number is random, and a 3*3 embark will have 1-4 spires (it cannot align completely, so the number is random within that range.

The Region Manipulator tool allows you to shift spires within their 2*2 grids so you can increase (or decrease) the number of spires, e.g. 4 spires in a 2*2 non aligned embark (this also happens naturally, of course, but if you want it to match other search criteria as well it might not be present naturally.).
Title: Re: DFHack plugin embark-assistant
Post by: DerMeister on September 15, 2019, 02:59:29 pm
Candy spires are not sites, and thus not shown on the embark overlay. However, the plugin allows you to search for embarks with a given minimum number of spires, and the results will match only such sites.
There are 64 spires in each world tile, and they're randomly distributed within 2*2 mid level tile blocks aligned with the edges. Thus, a 2*2 embark flush to any corner will have exactly one spire, which randomly appears in one of the mid level tiles. If you're not aligned with the 2*2 grid the number is random, and a 3*3 embark will have 1-4 spires (it cannot align completely, so the number is random within that range.

The Region Manipulator tool allows you to shift spires within their 2*2 grids so you can increase (or decrease) the number of spires, e.g. 4 spires in a 2*2 non aligned embark (this also happens naturally, of course, but if you want it to match other search criteria as well it might not be present naturally.).
I want embark on dark fortress with candy spire in embark area.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on September 15, 2019, 05:44:27 pm
Quote
It's largely a matter of which situation you want to optimize for:
a) Minimize the time it takes to search a full set of potentially matching world tiles; or
b) Minimize the time it takes to search a sparse set of potentially matching world tiles.
Now, if the cost to a) of achieving b) is small, it may be worth aiming for b).

Thank you for the fast reply.
Reading it I realized I need a much deeper practical understanding of how the plugin works - for example if all "attributes" describing a world tile are being extracted/loaded during a search run, even if there is no corresponding criteria that requires those attributes for matching.
So I'll set up the development environment and try to get the build/compile working with the latest version from git.
Then some light debugging ;D
That should help me to test and verify my assumptions - if they hold (probably a medium to big if) I might have an idea how to get a "cache" (=> actually an index) that can hold key information to speed up subsequent searches with a lot less than 30 GB of memory. Or I'll just realize that I was overly optimistic :D
I'll let you know as soon as there is something to share.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 16, 2019, 01:50:56 am
Everything is not retrieved for every world tile. If the top level check rules out a match the tile is stepped into and out of after the first scan, without any processing. On the first one the data that's collated on the world tile level has to be collected, and that basically means collecting everything.
The real memory killer here is the geo biome derived info, as each mid level tile has one boolean vector for metals, one for economic materials, and one for any non organic material, and I think those vectors are 5-600 long.
Another thing to consider is that the memory usage shouldn't approach 2 GB, as that would crash the 32 bit DFHack.

However, stepping onto a world tile takes time, as DF has to generate all the mid level tile information for the all tiles in that world tile, so skipping 10 tiles can save some time, and even more time can be saved if you can skip loading a feature shell (through a diagonal movement instead of one horizontal and one vertical in either order).

It can only be good to have more eyes looking at the code and trying to improve it.

@DerMeister: If you search for candy spires and then look at tiles with dark fortresses (they're clearly visible, so you don't have to search for them), you can select embarks that have spires. Since dark fortresses tend to take up a whole world tile, there should be 64 spires the search can locate. You can also use Region Manipulator to get the spires displayed as an overlay, and thus clearly visible.
Note, however, that dark fortresses tend to be full of goblins, which not only means there's a risk of rather rapid extermination of the embark team, but also an extreme slowdown due to the excessive number of units at the site. Also you'd have to use DFHack's Embark Anywhere to be allowed to embark on top of a settlement.
Title: Re: DFHack plugin embark-assistant
Post by: DerMeister on September 16, 2019, 07:57:56 am
Everything is not retrieved for every world tile. If the top level check rules out a match the tile is stepped into and out of after the first scan, without any processing. On the first one the data that's collated on the world tile level has to be collected, and that basically means collecting everything.
The real memory killer here is the geo biome derived info, as each mid level tile has one boolean vector for metals, one for economic materials, and one for any non organic material, and I think those vectors are 5-600 long.
Another thing to consider is that the memory usage shouldn't approach 2 GB, as that would crash the 32 bit DFHack.

However, stepping onto a world tile takes time, as DF has to generate all the mid level tile information for the all tiles in that world tile, so skipping 10 tiles can save some time, and even more time can be saved if you can skip loading a feature shell (through a diagonal movement instead of one horizontal and one vertical in either order).

It can only be good to have more eyes looking at the code and trying to improve it.

@DerMeister: If you search for candy spires and then look at tiles with dark fortresses (they're clearly visible, so you don't have to search for them), you can select embarks that have spires. Since dark fortresses tend to take up a whole world tile, there should be 64 spires the search can locate. You can also use Region Manipulator to get the spires displayed as an overlay, and thus clearly visible.
Note, however, that dark fortresses tend to be full of goblins, which not only means there's a risk of rather rapid extermination of the embark team, but also an extreme slowdown due to the excessive number of units at the site. Also you'd have to use DFHack's Embark Anywhere to be allowed to embark on top of a settlement.
Spires is not visible. How make them visible?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 16, 2019, 08:33:33 am
@DerMeister: As I said, spires are not displayed by this plugin. Instead, you search for matching embarks and embark in one of the matches.

The alternative, as mentioned as well, is to use the Region Manipulator, which does provide a display of spires: http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345 (http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345).
Title: Re: DFHack plugin embark-assistant
Post by: DerMeister on September 16, 2019, 08:54:42 am
@DerMeister: As I said, spires are not displayed by this plugin. Instead, you search for matching embarks and embark in one of the matches.

The alternative, as mentioned as well, is to use the Region Manipulator, which does provide a display of spires: http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345 (http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345).
And how make spires visible?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 16, 2019, 09:11:24 am
@DerMeister: As I said, spires are not displayed by this plugin. Instead, you search for matching embarks and embark in one of the matches.

The alternative, as mentioned as well, is to use the Region Manipulator, which does provide a display of spires: http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345 (http://www.bay12forums.com/smf/index.php?topic=164136.msg7454345#msg7454345).
And how make spires visible?
The script has a fair number of help screens. Read those. Hint: it's one of the overlays available through feature manipulation.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on September 17, 2019, 04:46:24 pm
@PatrikLundell
Got the compile, build and debug working.
But now I really need some sleep...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 18, 2019, 02:13:59 am
I've taken care of the sleeping for you, so you should be ready to move on :P
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 20, 2019, 02:05:40 pm
@Telear: I've experimented with the code to get the plugin to work in a semi-non-interactive way, but can't get all the way. Trying to get the plugin to shut down itself crashes DF, probably because you can't dismantle it from deep in a call chain: the shutdown probably has to come from an "outside" thread, such as the key input one (and emulating the "q" input doesn't result in this thread shift).
What I've done is:
- Allow for a single optional case sensitive parameter "fileresult" to trigger a special behavior.
- When the parameter is provided, the file "./data/init/embark_assistant_fileresult.txt" is deleted if it exists.
- A search is triggered immediately, first loading the contents of the saved profile (I haven't tested without any profile available, but suspect it will just result in the starting profile, i.e. X*X embarks with nothing else specified).
- Once the search is finished, a second search is started off immediately (committed and accepted changes that are not yet released in a new DFHack release provides detection of "incursions" into mid level tiles (bits of the biome of neighboring tiles jutting into the mid level tile examined), and that results in mutual analysis dependencies along world tile borders that cannot be resolved in a single pass).
- Once the second pass is through "./data/init/embark_assistant_fileresult.txt" is created, the number of matching world tiles followed by a newline is written into the file, and the files is closed.
- That's it. From then on the plugin should work as per normal (although I haven't actually tried, apart from using the "q"uit command manually).

Thus, using external scripting, I would expect that you could:
- Start DF and generate a world.
- Use the world to enter the pre embark stage.
- Optionally delete "./data/init/embark_assistant_fileresult.txt" if that makes trigger detection easier/safer.
- Enter "embark-assistant fileresult" into the DFHack window.
- Detect the appearance of the "./data/init/embark_assistant_fileresult.txt" file.
- Read the results from the file.
- Feed "q" into DF (or "kill" into the DFHack console if you don't care about doing things nicely).
- Repeat (probably deleting the world first if it had no matches).

It can be noted that even if I would be able to get the plugin to auto shutdown, it cannot be made to return a tile matching number, because plugins already have a return code (a success or failure code the framework recognizes).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on September 20, 2019, 04:40:16 pm
@PatrikLundell
Haha, very thoughtful of you to take care of my sleep - still feel kind of tired though.
Actually I really need some holidays - so my mucking around in the code will have to wait a little longer - but I like the idea of first modifying the movement (diagonal + 10x) pattern to get to know the code better. Which already has me thinking about some details I will have to ask you about eventually.
Also I'm wondering: Is this here the right place for me to ask detailed questions or is there a more suitable place, github perhaps? Just don't want to cause bordome to the other members with my learning the ins and outs of DF plugin development and the specialties of embark-assistant.

One more thing though - might using marcos help Telear? (https://dwarffortresswiki.org/index.php/DF2014:Macros_and_keymaps)
And is there a way to get the output of the dfhack console directly into a log file?
That would allow you to just output the number of found matches into the console without the need for embark_assistant_fileresult.
But of course then the log-file would have to be monitored for new entries to shut down the game....

Cheers!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 21, 2019, 03:10:40 am
@RedDwarfStepper:
After making my previous post I continued on to look at modifying the movement logic, and it turned out to be a lot simpler than I thought, as well as uncovering that I'd missed to cater for a need to scan everything in the first scan to get the incursion logic working correctly when the original implementation only scanned on a "need to examine" basis. This results in the first scan taking a long time (basically the same as currently), while subsequent ones are a lot quicker if the number of preliminary matching world tiles is reasonably low.

I think this thread is probably the best place to discuss issues regarding the plugin: I don't think there's a huge crowd of people that would find lots of time being lost reading posts irrelevant to them, and there is at least some chance something posted might be of use to someone else. If there are protests about that assessment I'd switch to a separate thread in this forum.
Note that I'm definitely NOT an expert on plugin development: This is my first plugin attempt, and I wouldn't have been able to get it to work without help from others, in particular Lethosor. I'm also not a friend of git: it keeps stabbing me in the back, apart from using backwards logic and "help" and documentation that simultaneously drown you in words about a seemingly infinite number of variations, while at the same time managing to just tell you half of the ones you need to use leaving the rest in the dark.

I think macros would be of limited use to Telear, as the process requires things outside of the DF context, detection of triggers, and entering of "key presses" only when trigger conditions are fulfilled. A macro essentially compresses several key presses into one, but since the key presses are entered through a kind of script anyway, a few lines of key presses does the same as a macro does, with the sequence being repeated every time that sequence of the script is processed.
I don't know how to get stuff off the DFHack console, but I doubt it would improve the situation in that case, as the script then would have to process everything else written to the console, like the number of preliminary matches
Title: Re: DFHack plugin embark-assistant
Post by: clinodev on September 21, 2019, 05:50:24 am
I think this thread is probably the best place to discuss issues regarding the plugin: I don't think there's a huge crowd of people that would find lots of time being lost reading posts irrelevant to them, and there is at least some chance something posted might be of use to someone else. If there are protests about that assessment I'd switch to a separate thread in this forum.

I can't speak for anyone else who's subscribed to this thread, but I personally find these sorts of questions and speculations on what future versions of the plugin may or may not be able to do endlessly entertaining and informative, and sincerely encourage them.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 21, 2019, 06:05:43 am
It certainly wouldn't be a matter of shifting requests and discussions about those elsewhere, but it's rather a matter of whether discussions about this section in that file looks the way it does (or what it actually does), i.e. things that may be of little interest to those interested in the sausage, not how it's made, would be better off elsewhere. Currently I don't foresee such detailed discussions to take up so much of the thread that it would be hard to get the interesting bits, though.
Title: Re: DFHack plugin embark-assistant
Post by: ibanix on October 18, 2019, 07:48:56 pm
Did this ever get backported to 0.34.11? Still running on that version due to all the crashes in the latest version.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 19, 2019, 06:53:08 am
Did this ever get backported to 0.34.11? Still running on that version due to all the crashes in the latest version.
No, and it won't be. Doing that would require digging up a corresponding version of DFHack, modify that, and release such a version.
This, in turn, would require ensuring all the DF structures relied on being available in the old version (or added to it, after verifying they indeed were the same back then), etc.

I have no objections to you trying to perform that feat, but to get a release you'd likely have to do all the groundwork as well as persuading the DFHack maintainers to release your updated old DFHack version (and I'd secure a promise before starting to ensure the work won't be in vain). Of course, you can do the work "privately" by downloading a base version of DFHack to your computer and do the work there for your private use.

I'd recommend 0.40.24 if you're looking for stability, but I started with DF at 0.40.0X (6, 7?), so I've never seen the old version.
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on October 19, 2019, 09:20:37 am
Did this ever get backported to 0.34.11? Still running on that version due to all the crashes in the latest version.
No, and it won't be. Doing that would require digging up a corresponding version of DFHack, modify that, and release such a version.
This, in turn, would require ensuring all the DF structures relied on being available in the old version (or added to it, after verifying they indeed were the same back then), etc.

I have no objections to you trying to perform that feat, but to get a release you'd likely have to do all the groundwork as well as persuading the DFHack maintainers to release your updated old DFHack version (and I'd secure a promise before starting to ensure the work won't be in vain). Of course, you can do the work "privately" by downloading a base version of DFHack to your computer and do the work there for your private use.

I'd recommend 0.40.24 if you're looking for stability, but I started with DF at 0.40.0X (6, 7?), so I've never seen the old version.
for me 44.09 is the most stable version. i was able to play 3 ingame years without a crash.
Title: Re: DFHack plugin embark-assistant
Post by: ibanix on October 19, 2019, 12:03:28 pm
Did this ever get backported to 0.34.11? Still running on that version due to all the crashes in the latest version.
No, and it won't be. Doing that would require digging up a corresponding version of DFHack, modify that, and release such a version.
This, in turn, would require ensuring all the DF structures relied on being available in the old version (or added to it, after verifying they indeed were the same back then), etc.

I have no objections to you trying to perform that feat, but to get a release you'd likely have to do all the groundwork as well as persuading the DFHack maintainers to release your updated old DFHack version (and I'd secure a promise before starting to ensure the work won't be in vain). Of course, you can do the work "privately" by downloading a base version of DFHack to your computer and do the work there for your private use.

I'd recommend 0.40.24 if you're looking for stability, but I started with DF at 0.40.0X (6, 7?), so I've never seen the old version.

I don't have the skill, so I'll just wait until a stable version of 0.44. Thanks for answering!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 19, 2019, 05:04:32 pm
I don't think there will be any stable version of 0.44: You'll have to wait for the Villains release to stabilize, and hope Toady will start to adopt a new development strategy whereby he fixes critical bugs in the latest released version in parallel with the development of the next one (he'll need to adopt such a strategy for the Premium release onward,, but I've got no idea if he'll wait until the last moment or tries to ease himself into it during the Premium arc).

Back porting DF mappings a large number of versions is no simple task, and I don't think there are many who could do it (I don't think I could, beyond the reasonably trivial "yes, it seems to be exactly the same" cases). Adapting the plugin code to work with what it managed to port back (most probably some things would not be found) would be the "easy" part.
In addition to the difficulty of pack porting DF mappings, it's probably going to be a fairly substantial amount of work, even if you specifically aim for just the things used by this plugin.
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on October 19, 2019, 11:35:04 pm
On that backporting note: It can be very much not enough to merely edit the plugin calls from named fields to anons; some of the functions plugin asks from dfhack could be outright missing (not familiar enough with embark-assistant code to say for sure); this means you'd have to do some updates for relevant parts of dfhack as well.

Relevant parts can be determined by failure to compile, then looking at dfhack's github history of relevant files, then adding things in. Also, relevant files may be entirely missing in 34.11.

For as great a difference as this, I'd expect it to take weeks.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on October 24, 2019, 04:11:43 pm
@PatrikLundell:
I'm back from my vacation (quite a while actually) and I've been busy.
First with getting to know the code and then with doing preliminary tests with a nice little data structure called RoaringBitmap.
Basically it's a compressed bitset, that can hold a huge number of entries while needing way less memory than regular implementations like vector<bool>.
This makes it possible to index/cache all values that can be expressed as bool, including inorganics (tested). It also should work well for those numerical attributes that only have a few valid values like savagery, with each value being represented by a separate index. It probably won't work for values that have a wider range like elevation, also since that retrieving would get inefficient.
My first test held 6 bools (sand, coal, ...) and all of the inorganics for all mid_level_tile entries of a 257x257 world in ~ 200MB RAM.
I'm trying to get my head around the logic of incursion-processing (got your last version from github), which might by possibly moved into the index as well.
That might take a while, also I'll have questions :)
As soon as there is something to show I'll put it up on github.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 25, 2019, 05:11:05 am
Compressing the data into single bits per bit should indeed make it possible to reduce the memory needed a fair bit, at the cost of speed (which is important).
However, I'm unable to see how you can compress what you mentioned into 200 MB, as my quick calculation results in:
(264 non procedurally generated inorganics + 6 booleans) / 8 = 33 bytes *
257 *257 * 256 mid level tiles (= 16908544) => 557981952 bytes, i.e. about 560 MB.

Nevertheless, this might be a useful approach, although the speed impact will have to be investigated, and I'd definitely check the overhead of this RoaringBitmap thingie compared to doing it "manually". Note, though, that there are currently 3 vectors over the inorganics: one for all of them, one for metals, and one for economics. While the data itself can be stored in a single vector, it comes at the expense of then having to probe the appropriate indices for metals and economics, which may or may not turn out to be an issue.

Incursion processing is indeed complicated, made more so by the way Toady ended up representing the information so that it almost, but not quite, provided all the information needed to evaluate a world tile in isolation along the eastern/southern edges. As you can see, the incursion processing ended up with partial storage of the base information (notably excluding the inorganics) along the world tile edges, and I've considered whether it would be reasonable to expand that partial information storage to cover all mid level tiles, but haven't investigated that.
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on October 25, 2019, 08:33:40 am
It might be possible to compress the 264 inorganics by finding groups of frequently-appearing together inorganics, so if a geo_biome has 100111111 for layer materials, could mark the 1111111 as seven10(=111binary) 1s instead. It's probable that two adjacent embark tiles in same biome share lot of base geology, so there's no need to use memory for that on both of them.

But that trades even more memory for performance.

Also, caching search result should probably be a auto-off toggle. I imgine the common use case is quick enough or just single search, not needing the cache, where cache might be prohibitive on older systems attempting it on words on the boundary of what their RAM can support.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 25, 2019, 12:10:21 pm
Trying to analyze the geo biome for commonalities isn't a good idea if you want the plugin to work for modded geo biomes. It's true that neighboring tiles usually share the same geo biome, but they may not share their depth cutoff (which is where DF mis-reports deep metals/flux) or the soil erosion level (missing sand/clay/aquifer), and bunching together the geo biome results for multiple tiles more or less leads to re-processing the geo biome, in which case all you need to store is the geo biome index and the top/bottom level info (to account for soil erosion as well as magma sea cutoff). That, however, is expected to trade memory for measurable amounts of repeated processing, which is the current situation (which re-processes the geo biome, including erosion/depth cutoff determination for every mid level tile within every world tile that hasn't failed other criteria if such data is required, and for all tiles in the current world tile, for embark preview display purposes).

I expect the common use case to be a preliminary search with one or more refinements (typically either failing to find exactly what was desired, and so loosen the constraints, or finding lots of hits, allowing for additional conditions), in which case a cache comes in handy. Dual implementation with/without a cache seems like it will result in messy code (complexity that can actually be managed may be justified if the benefits to the users are large enough, though).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on October 25, 2019, 06:48:27 pm
Thanks for your quick feedback!

However, I'm unable to see how you can compress what you mentioned into 200 MB, as my quick calculation results in: ... about 560 MB
Ah, that is the nice thing about Roaring Bitmap: It's an inverted index, so you only add those entries to the index which for example have a river or coal, which results in a lot less total entries than 257*257*256 for every attribute/aspect
See here for a practical explanation
https://medium.com/@amit.desai03/roaring-bitmaps-fast-data-structure-for-inverted-indexes-5490fa4d1b27
and here for more details
https://roaringbitmap.org/about/
and being compressed it allows for sub-bit memory use per entry, depending on the data, see here
https://arxiv.org/pdf/1709.07821.pdf, page 20
Dense, non-random, sorted data produces the best results. During my experiments I used a RoaringBitmap to keep track of which mid level tiles were already processed, each one got an "id" which was calculated by its x,y,i,k-position, starting with 0 (y=0,x=0,i=0,k=0). In the end the bitmap contained all integers from 0 to 16908544 and it would have taken only 3kb to serialize it.

Nevertheless, this might be a useful approach, although the speed impact will have to be investigated
Absolutely, if it is even a little slower during the survey or the match phase it won't make any sense to pursue this approach any further.
But the data structure offers very fast set operations (union, intersect, ...) which allow for some nifty tricks when looking for a certain combination of attributes.
My idea was to sort the bitmap indexes ascending by size once the complete index/survey phase is over and always start by looking for matches in the smallest relevant index (e.g. probably volcanoes, waterfalls or other rare attributes). The fastest case would be no matches, which means the whole process could stop.
If there are any matches we iterate over them and look into the next (bigger) relevant index to see if there are any intersections and so on.

Note, though, that there are currently 3 vectors over the inorganics
I already stored them separately...  :D

Incursion processing is indeed complicated
Yes, I see that now. I had a look at your comments here
https://github.com/DFHack/df-structures/commit/caebec25986228d15a6e1179b0745fec83f97562
and boy is my head spinning. I'll probably have to look at the code again and create some sketches and/or schematic views of the mid level and region tiles and annotate them with my questions and how I think I understood the concept. And then you can hopefully tell me how it really works. ;D

Also, caching search result should probably be a auto-off toggle.
Yes, I also thought that might be a good idea - but for the big (257*257) maps which would benefit the most the users probably have a beefy system with enough ram. Just loading the map needs more than 1 GB ram already.

But I really need to prove all those hunches, theories and ideas, so I'll have to get a minimal example/proof of concept working, which still might result in the discovery that it just won't work for some reason I haven't thought about yet.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 26, 2019, 06:20:14 am
OK, so if I understand it correctly (having read the two first papers and only looked at the last, boringly academic one), you're changing the storage of properties from being per mid level tile bitmaps over properties to be global per property, "indexed" by the mid level tile, in which case I'd expect most of them to be sparse and without significant runs, resulting in storage as arrays of MLT indices, which ought to require significantly less memory (at the expense of binary searches) than retaining the current MLT level data in memory. I'd also expect the metal lists in particular to be short, but also that most of the economics lists to be rather short, although very low "scarcity" world gen values would make the lists a bit longer.
Lists over savagery/evilness would probably be rather dense for the normal (middle) values, resulting in bitmaps that don't compress well, while the other values would result in a lot sparser lists/bitmaps. In any case, every MLT has exactly one of the three values in each range as their primary value, and may have one or both of the other two as incursion contributions.

It can be noted that this implementation strategy change would force the use of storage of all criteria in memory, and great care has to be taken to ensure the memory usage is kept in check: I do not agree with the assumption that a full size world equates the 64 bit version of DF and hence "sufficient" amounts of memory, as you could create a normal sized embark in a full size world before DF provided a 64 bit implementation, and nothing fundamental has happened since then. The main reason to keep away from large worlds in the FPS drain caused by world activities. If a full world uses 1 GB (I haven't checked), that would mean this plugin would be required to stay well below 1 GB to work with the 32 bit Windows DF version.

Incursions: It took quite some time to understand what the original comments in the DF structures meant and figure out how they worked, and I have absolutely no idea how the person who wrote that managed to figure it out. You don't want to know what my initial attempts to code the logic looked like, as it was an absolute mess of cases within cases.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on October 29, 2019, 07:34:29 pm
OK, so if I understand it correctly ...
You are absolutely correct, this would be some kind of database-table or -index design.
I did quite a poor job of explaining it properly: It is kind of a database-table or -index design.
Also I took another look at the memory requirements for a std::vector<bool> and it seems that in many cases it would be cheaper memory-wise to use one of those - even for 257*257*256 entries (~ 2Mb).
The sparse inorganics might be a notable exception, I'll have to test that.
So I have to ask: What do you generally think about the idea to change the way the data is stored?

It can be noted that this implementation strategy change would force the use of storage of all criteria in memory, and great care has to be taken to ensure the memory usage is kept in check: I do not agree with the assumption that a full size world equates the 64 bit version of DF and hence "sufficient" amounts of memory, as you could create a normal sized embark in a full size world before DF provided a 64 bit implementation, and nothing fundamental has happened since then. The main reason to keep away from large worlds in the FPS drain caused by world activities. If a full world uses 1 GB (I haven't checked), that would mean this plugin would be required to stay well below 1 GB to work with the 32 bit Windows DF version.
Again you are right - assuming that everybody has a lot of ram was a misconception.
That's why I'm looking for ways to save as much memory as possible without ruining the performance.

Might I ask you a favor?
I uploaded the save (http://dffd.bay12games.com/file.php?id=14584) and profiles I use for getting an idea how much memory it would take to "index" everything for a large world.
Could you please run an initial "find embark" with the included embark assistant profile once with the current version of the plugin and once with your latest version (it's https://github.com/PatrikLundell/dfhack/tree/embark-assistant isn't it?) and tell me how long it takes to finish the first time and how much additional memory is allocated in each case?
That would help me to better gauge how the plugin performs on another system.

I really would like to make faster progress - but currently I only have the nights to do some coding. While I like it, it's not my most productive time...
I got some refactoring done while reading the code, which resulted in a slightly smaller release dll, if you want to take a look:
https://github.com/bseiller/dfhack/tree/embark-assistant/plugins/embark-assistant

Ah one more thing: I trying to profile the memory consumption with MS VS, but all I see is "unresolved allocations" which really doesn't help a lot. I assume the reason for this is how dfhack is "integrated" with DF, as the profiling works just fine in a test project (exe). Any clue you can give me on how to get the memory profiling working is very much appreciated! Or perhaps you know where or who to ask
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 30, 2019, 05:56:12 am
I made the crude measurements (task manager) asked for:

          Old    New
DF only    1076.8 1023.1
EA started 1115.2 1579.0
Max        1139.8 16XX.X
Done       1127.5 1592.3
Time         5:50  26:50

I hadn't expected the memory usage reduction to happen as early as I did for the later version, hence I didn't remember the values when it suddenly shrank, but they were probably low (1607,X?).

I have no experience profiling C(++), and the profiling I have done were on other languages on other platforms. I would assume profiling a DLL as part of a program to differ from profiling a program, though, in particular if there's no symbol information for the hosting program. I'd try to look for something that tried to restrict the profiling to the known part of the executable (i.e. the DLL), or to separate the known locations from the unknown host ones.

Edit:
I had a quick look at the changes, which were a lot lighter than I would have expected when the word "refactoring" is used. I'm a bit surprised that the code would get smaller, though, as I had expected the compiler to be smart enough to factor out common parts.

I have two style comments, though:
- As opposed to the C crowd, I don't have a pathological aversion to typing, so I would have used readable identifiers to a much larger extent than the TLA/FLAC usage. (TLA = Three Letter Acronym, FLAC = Four Letter ACronym, which is not a standard one).
- I find camel case to be extremely ugly and instead separate words using underscores (or, occasionally, use Germanic [and DF!] word mashing [and those languages somehow do just fine without camels]).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on October 30, 2019, 05:53:35 pm
I made the crude measurements (task manager) asked for:

          Old    New
DF only    1076.8 1023.1
EA started 1115.2 1579.0
Max        1139.8 16XX.X
Done       1127.5 1592.3
Time         5:50  26:50

Thank you for taking the time to get these numbers.
Ok, that's interesting - for me the previous version takes around 8 minutes. And the new, unchanged version around 13 -
Memory wise I see pretty much the same, a little more in both cases, but the ratio is about right here

I had a quick look at the changes, which were a lot lighter than I would have expected when the word "refactoring" is used.
Hehe, I'm just starting to pick up speed - I don't want to break something right away. But we'll get there

I'm a bit surprised that the code would get smaller, though, as I had expected the compiler to be smart enough to factor out common parts.
Yeah, me too. Actually changing variable names doesn't make a difference, but it seems function call (like .at()) aren't optimized away with the default project settings.

I have two style comments, though:
- As opposed to the C crowd, I don't have a pathological aversion to typing, so I would have used readable identifiers to a much larger extent than the TLA/FLAC usage. (TLA = Three Letter Acronym, FLAC = Four Letter ACronym, which is not a standard one).
- I find camel case to be extremely ugly and instead separate words using underscores (or, occasionally, use Germanic [and DF!] word mashing [and those languages somehow do just fine without camels]).
Done and done.

Ok, so before I really break something, you don't happen to have a "test world" that helps you to verify any changes?
I looked into "Perfect World" but it seems impossible to just paint the biomes and other stuff exactly like you want it.
A pocket world with some defined rare combinations (like e.g. volcano & waterfall in the desert) in different embark tiles could be a nice tool to check changes.
Speaking about pocket worlds, it seems that at least with my build using embark assistant in pocket worlds crashes the game. Can you reproduce that? If I recall correct it already happened before I started changing stuff...
The crash is provoked around here: https://github.com/PatrikLundell/dfhack/blob/79791505660f3dc55895aa103c8907214ec10afb/plugins/embark-assistant/survey.cpp#L1369
Title: Re: DFHack plugin embark-assistant
Post by: Pvt. Pirate on October 31, 2019, 05:43:52 am
I had a quick look at the changes, which were a lot lighter than I would have expected when the word "refactoring" is used.
Hehe, I'm just starting to pick up speed - I don't want to break something right away. But we'll get there
:D Hehe, it always comes to the point of breaking something eventually and then taking a step back and going slower again and succeeding.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 31, 2019, 09:34:17 am
Thanks for the crash report.

It took a bit of time to find out what was wrong, but it is indeed a bug.
The line should be
Code: [Select]
            tile->region_type[i][k] = world_data->regions[tile->biome_index[mlt->at(i).at(k).biome_offset]]->type;
i.e. "biome" -> "biome_index".
The reason it crashes only on pocket worlds is that the number of regions in those worlds tend to be fewer than the number of biome types, i.e. the index passed in was the biome type, but was interpreted as the index of the region.
The bug should screw up the reasonably (I think) uncommon searches for region types when it doesn't cause a crash.

I use my own tweakmap http://www.bay12forums.com/smf/index.php?topic=161188.msg7228166#msg7228166 (http://www.bay12forums.com/smf/index.php?topic=161188.msg7228166#msg7228166) tool to create PSV worlds, as I consider the DF vanilla tool to be a serious contender for the worst interface ever and after coming to the conclusion that I'd have to create an image to feed into Perfect World for it to be useful (I originally wanted to feed the PSV values extracted from an existing generated world for tweaking), and if I was going to do that, I could just as well place the actual biomes wanted as the pixels.
However, volcano placement can only be suggested, although I think it would be possible to get close by restricting the number of tiles with high volcanism. Rivers and lakes are completely up to DF (although both can be hacked after world gen, with a lot of patience, but the only ways to save the results are either to do the tweaking during world gen [e.g. by breaking in directly after the generation of those features, but before history, etc.], or by embarking).
Also note that both Salinity and Evilness are missing from the set of PSV values, so there parameters can't be controlled.
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on October 31, 2019, 06:17:42 pm
You can place volcanoes by exactly 100 volcanism in desired tiles + desired number of volcanoes in min volcanoes. Though that's still just somewhere in world tile, not any more accurate. Rivers&lakes yeah you can only suggest with elevation, not place.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 01, 2019, 06:01:01 am
The Mid Level Tile (MLT) placement of volcanoes is calculated by DF when the tiles are generated on the fly, presumably using an RNG seed hidden away somewhere. It's possible to hack the location of a volcano while the world tile is in focus (so you can place it where you want for an immediate embark), but changing the focus away and back causes the volcano to revert to its original MLT location.
Hacking a new volcano into a world tile has DF assign it a "random" MLT location within the tile. As with natural volcanoes, the location remains the same when you change focus and return to the tile.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 07, 2019, 05:08:44 pm
Thanks for the explanation concerning the creation of specific region.
I downloaded the scripts (haven't had time to test them) and had a look at https://github.com/PatrikLundell/scripts/tree/own_scripts.
I couldn't find exportmap.lua in the repro - does it have another name there?
Are the dropbox files the latest version?
What does the TLA PSV stand for? - I couldn't find any definition...

Meanwhile I broke something with my refactoring and it took some time to find the error - now it works as expected.
I might refactor more code while I prototype the index and keep it in a separate branch which will allow for easy merging if you feel that the code is up to your standards.

Trying to profile the heap usage I shot myself in the foot with gflags and debug heaps which resulted in a much bigger memory footprint and much slower search times due to the profiling overhead.
I had forgotten that I activated it and the config hides in the registry...
That got me thinking: Could it be that the second column (incursions included) was so slow because it was a "RelWithDebInfo" build?
I made the crude measurements (task manager) asked for:

          Old    New
DF only    1076.8 1023.1
EA started 1115.2 1579.0
Max        1139.8 16XX.X
Done       1127.5 1592.3
Time         5:50  26:50


For now there is one more question: What was the motivation to keep the inorganics in mid_level_tile in three separate vectors?
In my test world there are 265 inorganics (metals + economics + minerals), each with a unique index, no overlap...
Does modding change that?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 08, 2019, 07:48:12 am
I'd missed to add exportmap to own_scripts, and tweakmap wasn't the latest version in either place (fixed now).

PSV = Pre Set Values. That's the specification of temperature, savagery, rainfall, elevation, volcanism, and drainage DF allows advanced world gen to specify per world tile.

RelWithDebInfo may well be a factor in the sluggishness. Unfortunately, my attempts to compile it with Release has met with failures so far (the latest one being a spontaneous reboot of the computer for no apparent reason), so I haven't been able to test it yet.

The reason for keeping inorganic in three vectors is ease of searching with a guess that it ought to be faster than a more complex logic. Also note that once the decision to regenerate/discard info, storage size is much less important than speed. There isn't anything I'm aware of that would stop an inorganic from being both a metal and something that's involved in a non metal related (modded) reaction, and I thought the minerals list was complete, i.e. listed all minerals, regardless of whether they are present in the other lists (with clays showing up in both lists). Metals won't show up in that list because they're never actually present in their metallic form (native gold isn't actually a metal itself, but a source for a reaction that produces the metal) in the vanilla game.
It's quite possible to have a single list of everything found either natively or resulting from a metal production reaction and then have three separate global lists that contain the indices of the inorganics that match the criteria for each list. Thus, to identify the minerals, you'd iterate over the "minerals" list and check whether the corresponding index in the compound list for a tile is true or not, and similarly for the two other (much shorter) lists. Note that to generate the lists of minerals in DF you'd have to figure out a way to determine which inorganics the game can include in all the geo-biome positions, which may be non trivial (when I asked, the forum didn't know how to determine if an area is "alluvial", and some minerals (opals, I think) appear only in those places, but that may not be an issue here: it may well be that just adding "alluvial" ones to those that can readily be identified is sufficient).
There are probably other ways to achieve the same thing, so if trying to save space it's definitely possible to store the info in a single vector and process it to determine where different pieces fit,and you'd only do that for searches if the search criteria look for that specific info. For the embark location overlay you'd have to do the complete processing, but that's only for the tiles in that embark, and that changes at human speed, which means the processing time isn't important.

Edit:
Finally got Release working (it help to try to run the right DF copy...). As you suggested, it showed a dramatically improved performance at 7:30, with the high and final memory usage a 1601.7 MB.

Edit 2:
I've been thinking, and believe it's a mistake to try to massage the current inorganics presence storage. All you really NEED is two bytes to store the first and last layer of the geo biome present for each MLT (in addition to the index of the geo biome itself, which is currently stored), as all the rest of the info is available from the geo biome itself (And since the two values are in the range 0-15, you can actually store both of them in a single byte). To get the first/last layers we could cut away a fair bit of the code from the modified Prospector code of the MLT processing (the removed code would still be needed elsewhere to extract the actual inorganics, though).
With that basic information stored, you can either process the geo biome each time you need the data, or you can try to pre process the geo biomes to speed up the information extraction.
- The layers potentially worn away by erosion are all soil layers, and DF never seems to generate more than 4 of those. It's possible to hack the geo biome to get more soil layers and/or deeper soil, and DF can erode up to 10 Z levels, if I remember correctly. The suggestion below doesn't actually make any use of this info, though.
- DF doesn't use more than 16 layers of the geo biome even if hacking has added more (DF stretches the last one to fill the gap to the magma sea if needed).
This means that one possible approach would be to make a bit array for each layer of each geo biome and then merge the ones you have in each MLT with OR operations (16 layers * 33 byte bit array * X geo biomes). Even if DF doesn't croak at a silly max size PSV world with a checkerboard layout (forcing each world tile to get its own geo biome), you'd still not use more than 35 MB to store the info in a more convenient format than the geo biomes themselves.

Returning to the logic of the 3 lists (as per the current implementation), they don't help with embark matching, as you can just as well check for a True in a merged list as you can in a list dedicated to the category you're checking. The place where it is of some help is when generating the embark location resource lists displayed, but it's a marginal extra effort to iterate over Economics and Metal indices lists to check against a presence in a common list, and that processing happens at human speed anyway. Thus, it could have been implemented better.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 12, 2019, 06:09:29 pm
I'd missed to add exportmap to own_scripts, and tweakmap wasn't the latest version in either place (fixed now).
Thanks!

Also thanks for the in-depth explanation on how the inorganics work and on the why the data is structured the way it is!

Edit:
Finally got Release working (it help to try to run the right DF copy...). As you suggested, it showed a dramatically improved performance at 7:30, with the high and final memory usage a 1601.7 MB.
Ah, that sounds more like it - but damn - your system/CPU must be quite a little bit beefier than mine.

I spent some time with profiling the plugin (had to set up a new release-optimized-but-with-symbols config, as the "RelWithDebInfo" performed quite different compared to "Release").
After that I profiled just the pure movement code (embark_assist::matcher::find + embark_assist::matcher::move_cursor) without any real surveying and matching.
And - I had forgotten - as you already had said: a lot of the time is being spent in the movement part of the code

One complication is that DF uses a data structure with "feature shells", i.e. 16*16 world tile blocks, and loading those take a significant amount of time (about half of the total search time), which has caused me to ensure the world is processed one feature shell at a time
After removing all of real logic it still took around 8 minutes to iterate over the whole large map - instead of the 12 minutes with all the logic.
I also played around with threads a little - to no avail as of now.
So speeding up the search logic itself solves only half the problem, as the main-loop/interaction with the DF core takes so much time.
I really had hoped to find an "easy" solution to speed things up.
Any ideas how we could go about to make <screen->feed_key> "faster" or parallelize it?
I'll need to regroup and do a little more work on the index proof of concept to get my spirits up ....

PS: I could upload the profiling report if you want to have a look, assuming that you use MS VS...
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on November 12, 2019, 06:36:35 pm
I'm not certain if embark-assistant already uses it, but frames are just calls of logic() on dwarfmode viewscreens - this could be helpful maybe?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 13, 2019, 06:40:58 am
My PC was a just below the very top off-the-shelf ones when I bought it quite a few years ago, but it's showing its age, actually, by having trouble with graphics intensive games (which obviously doesn't include DF).

I don't think there is anything you can do about the movement code to get any significant improvement, as the bulk of the time spent is waiting for DF to load feature shells and to generate MLT data for the current world tile. The most important thing here is to reduce the number of these calls to the absolute minimum, and I think the current code is close to that for the first pass (I believe every world tile is passed through once, with each feature shell loaded once, except for the initial movement up to the starting position).
You can't parallelize DF feature shell/world tile data loading/generation unless you run multiple copies of DF and somehow synchronize them to process different parts of the world, which seems rather messy.

I can understand that generation of MLT data from seeds takes some time, but I'm still wondering why DF takes so long to generate feature shells as the DFHack mapped data structures aren't that big. It may be that there's some significant file reading involved, but I haven't investigated the cause as I believe it's something we can't do anything about anyway.
In short, I believe the DF MLT data generation and feature shell loading are things we just have to live with, and deal with by ensuring we keep those activities to a minimum.

The big gain would be to remove the need to repeat the actual movements for subsequent searches, i.e. to collect all the info requiring movement on the first pass and then use that info together with what's available statically from DF structures for the matching. That, however, requires intelligent storage of the information that's required, optionally together with that which is costly to collect, while the rest would be collected from the DF data structures available statically when it's needed.

There's also a psychological aspect to the process: we can't collect data for minutes without providing some kind of progress feedback to the user (which is why the feedback used by DF's native search is emulated currently).

I am using MS VC, but I currently wouldn't have any use for the profiling report. I don't think it's a good idea to mess around with trying to optimize code in parallel with someone else trying to revise it. However, it would be useful when you're done with your activities.

I don't understand Fleeting Frames' comment. I don't believe the time it takes to do the actual calling is a great issue, but rather the time DF spends doing what those calls trigger (which is what we need DF to produce, so we can read it). I certainly would like to have a way to move DF's focus directly to a specific world tile rather than go there in steps of 1 or 10 tiles through simulated key presses, as that would be much more convenient to use, but I doubt it would make any significant difference from a performance perspective.
Title: Re: DFHack plugin embark-assistant
Post by: Fleeting Frames on November 13, 2019, 07:44:34 am
The comment was in case there was idle processor time between embark-assistant and DF i.e. if embark-assistant waits a frame until DF has done its thing rather than reacting that millisecond. Of course, if there were, you could speed up search also by increasing fps, which I doubt is the case from looking at "do nothing" search.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 13, 2019, 08:36:44 am
Given that DF isn't doing anything pre embark apart from displaying data and reacting to player key presses, it shouldn't really matter if we could save up to 10 ms (i.e. up to 7 seconds for a full size map at 100 FPS, which is the FPS I think we get, and half of that time on average). A save of 100 ms per movement would have been significant, though.
In all, a good idea that doesn't seem to that relevant in this particular case.

Edit: Something different, but not worth double posting:
An implementation I haven't been happy with is the embark matching at the actual embark level. Currently all embark combinations are examined for a world tile that may have a match in it, with embarks rejected one at a time on the detection of a mismatch. A more intelligent approach would be to invalidate all rectangles that are invalidated by an absolute criterion mismatch (e.g. "no evil anywhere") and start embark rectangle evaluation with checking for this early rejection.
I can think of two approaches to achieve this:
- Proceed as now, but as soon as an absolute mismatch is found, all starting MLTs of rectangles that would include the offending MLT would be marked as rejected, and so be skipped after checking this flag.
- Pre-process all tiles individually and mark as in the previous alternative (skipping pre-processing of tiles invalidated), storing the collected data for each tile until it can be used for compound evaluation. This may be more complicate than the other alternative and require storage of more info, but might have a slightly better performance because you don't do the full processing up until finding the rejection. However, added administration might cancel out the gain.
Title: Re: DFHack plugin embark-assistant
Post by: Rekov on November 22, 2019, 03:32:59 pm
Possible problem with waterfall detection. I tend to use the embark-assistant location finder because the options are so much more useful than built in search. I have noticed that sometimes it misses what would seem to be viable locations.

For example, I ran a search with the following values:

X Dimension: 4
Y Dimension: 4
Min River: Minor
Waterfall: Yes
Freezing: Partially Frozen

Then, I tested turning off each of the requirements one by one. This site, which definitely has a waterfall isn't included in the search results if I have Waterfall: Yes, but does show up if I have Waterfall: N/A

(https://i.imgur.com/Ap4hoYb.png)
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 23, 2019, 04:18:26 am
Hm, I have a suspicion that there might be something related to the rivers joining that somehow scrambles the logic. If you could provide the save and a description of where the site is located I'll take a look and try to figure out what's going on.

Edit: I hope the statement about sometimes missing viable locations refers to the waterfalls. If there are other cases as well, those are other bugs that ought to be fixed, once they are made known.
Title: Re: DFHack plugin embark-assistant
Post by: Rekov on November 23, 2019, 01:01:44 pm
Yeah, I'm just talking about the finder not detecting all waterfalls.
I did a simpler search with just Min River: Stream, Waterfall: Yes

You can just generate a world, do this, and randomly trace along streams, rivers, etc, and you will find waterfalls that didn't get picked up by the search.

(https://i.imgur.com/W9GFBPX.png)

(https://i.imgur.com/fCNOPbk.png)

Here (https://mega.nz/#!lI5AGYqK!25jdKC6tgZD6BazqAshPC6Xj7MHHlPMY7NtgPCs47Ek) is the region this is from, but like I said, it's pretty easy to find instances like this in any world.

Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 24, 2019, 03:26:04 pm
Thanks for the save: it's a lot easier when show exactly what to look for and where, even though it was rather easy to find once I knew what to look for.

OK, I've found the problem: The "active" field of the horizontal/vertical river info isn't a boolean, but -1, 0, 1, and I checked for 1, so about half of the river tiles were missed. This is a river issue, not a waterfall one, but if the river isn't detected, neither is a waterfall in it.

While thinking about what the problem might be, I realized there was something else missing: for some weird reason DF doesn't generate info for some river tiles (at the Mid Level Tile level), but deduces their presence from neighbors (to the south and east, it turns out), and the logic wasn't known (at least not by me). I've tried to investigate it and think I've gotten it to work (but I still don't understand the logical reason behind it). Searching for single tile embarks with rivers on them should match the DF display, and does so (on my system) except for two edge cases I won't bother fixing:
- River sources/sinks to the North and to the West of the river are implicit, like the bends. However, some river sources/sinks are in lakes and some sinks in oceans. However, DF does generate rivers on ocean tiles, including sources (or if they're sinks). I don't know how to determine when not to generate river indications for those cases.
- DF generates river info for glaciers, but doesn't display any rivers, which makes logical sense as they'd be frozen all year around anyway. I expect that can indicate waterfalls as well, but you'd have to wait for the next inter glacial period to embark there if you want to enjoy them...

As far as I can see, there's no issue with joining rivers, at least my looking around with single tile river matches has worked correctly for all the cases I've looked at (randomly walking around the map and look for mismatches), so that was a false lead.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 24, 2019, 07:19:39 pm
@PatrikLundell: Just to let you know: I'm still at it.
The whole family caught a cold which forced my first to do theoretical experiments and later on allowed for pen-and-paper programming.
I'll incorporate the waterfall and river fix...

PS: If you feel inclined to play around with the latest work-in-progress, your invited to take a look/check out
https://github.com/bseiller/dfhack/tree/embark-assistant-index/plugins/embark-assistant
Currently it only feeds into the index, no queries so far. But that is what I'm working on in a standalone command line project, which allows for faster development as the startup time is much shorter.
Also the styles are not up to your standards - I started with it before your feedback - I change the names of members and functions as I go.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 28, 2019, 05:45:01 am
Taking care of the real world takes precedence over the virtual one...

I'm just starting to look at what you're at, and probably misunderstand half of it, so the comments should be taken with that in mind.
- defs.h; inorganics: There are more than 256 of those, so they won't fit in unit8_t (assuming that's what's supposed to be stored).
- index.h: The plural of "index" is actually "indices".
- index.h: I don't see the point of creating maps of the names of various inorganics, as you can easily extract those from the DF structures. If it's some kind of backward indexing I'd just store the index of the corresponding inorganic (in the DF structure).
- index.h: As discussed earlier, it would make sense to merge the three (four?) inorganics vectors of maps into one, but it makes sense trying to get things to work first before trying to optimize them.

index.cpp:
  - Index::setup: It seems you make the assumption all worlds have x and y dimensions that are the same. That doesn't hold (mine are 17 * 129, for instance).
  - Index::createKey (and setup, maxKeyValue): Does the range matter? If it doesn't I'd just make the key out of the lower 12 bits of x and y, plus the lower 4 bits of i and k, with a sanity check to ensure the world dimensions don't exceed the limits (which they can't in vanilla, and it seems from another thread they can't approach those values). The next point indicates the value range does matter, though.
  - Index::add: It seems this operation relies on the order in which the keys are added, and that order does not work well with either DF's feature shells or an efficient processing of world tiles without feature shells (unless there's some way to move directly from the last world tile of a row to the first world tile of the next one). A comment explaining what's special with 511 would be useful: I can't figure it out.
  - Index::add: I'd change the code checking for duplicate keys to a one liner (which I usually avoid) and comment outthe whole line when not used, rather than just the output. The compiler will have to perform the function call unless it can somehow deduce it doesn't have side effects even if there's nothing to do when true.
  - Index::add: Is there a reason for the omission of code inside the candy check? The later storage of level?
  - Index::add: I'm not sure what you're after with the (explicitly redundant) checks for various layer materials (not sure if it covers veins). If activated, it would exclude gems, for instance, and regardless, if someone has hacked in something, I don't see why it should be filtered out (And I just realized someone hacking in steel as a layer would get it filtered out if all inorganics were merged, but the issue would still be isolated to metals, and it would be possible to handle metals only separately).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 29, 2019, 08:09:16 pm
Oh wow - thank you very much for taking the time to look into in detail!
Ah, the code is still full of constructs that I installed to help me get my bearings and to (dis)prove my assumptions how DF and the plugin works.
A lot of those can and should be removed or properly commented if it makes sense to keep them for debugging purposes.
Now to your comments:

Taking care of the real world takes precedence over the virtual one...

I'm just starting to look at what you're at, and probably misunderstand half of it, so the comments should be taken with that in mind.
Very true, especially if the real world does not give you a choice about that :)

Having read your comments I can tell you: Even if one of them did not point out an error or misconception of mine it at least made clear that I need to externalize my thoughts (by comments!) and remove old code more eagerly. Especially since code turns into legacy code so fast, even if I'm myself the author.

- defs.h; inorganics: There are more than 256 of those, so they won't fit in unit8_t (assuming that's what's supposed to be stored).
That seems true for my test world (but might even have been wrong there) but this was a put there to try improve performance where vector<bool> seemed slow - which they are in the debug build as some optimizations only are made for release builds. Has been removed.

- index.h: The plural of "index" is actually "indices".
Changed - hehe, in my mother tongue it would have been me to point this out :)

- index.h: I don't see the point of creating maps of the names of various inorganics, as you can easily extract those from the DF structures. If it's some kind of backward indexing I'd just store the index of the corresponding inorganic (in the DF structure).
I'm lazy and wanted to be able to look the name up during debugging and have it ready when writing the "report" at the end of the survey/index phase.
As those names also are used as part of the file names when writing the indices onto the disk (Index::outputContents) I thought it might be nice to have them around so the writing process was not being made more complicated or slower by the sequential (?) look up. But the idea that that could be complicated might have its root in my narrow understanding of the DF structures.

- index.h: As discussed earlier, it would make sense to merge the three (four?) inorganics vectors of maps into one, but it makes sense trying to get things to work first before trying to optimize them.
Exactly my thought - the fourth vector (inorganics) will replace the three others as soon as I'm sure that I'm not missing anything.

  - Index::setup: It seems you make the assumption all worlds have x and y dimensions that are the same. That doesn't hold (mine are 17 * 129, for instance).
Oh boy - that one is - I never even knew that is possible!
Fixed this by removing world_dims and using worldgen_parms.dim_x and worldgen_parms.dim_y instead

- Index::createKey (and setup, maxKeyValue): Does the range matter? If it doesn't I'd just make the key out of the lower 12 bits of x and y, plus the lower 4 bits of i and k, with a sanity check to ensure the world dimensions don't exceed the limits (which they can't in vanilla, and it seems from another thread they can't approach those values). The next point indicates the value range does matter, though.
The range of the key values by itself does not really matter - apart from the fact that there is an upper limit (MAX(uint32_t)) - but the value is currently used to reserve memory for the vector keys_in_order (of addition that is), which in turn is used to help test performance. Roaring works best if the keys come in strict ascending order. It still works fine of they are "random", but in that case it performs better if it gets a little help now and then by calling runOptimize and shrinkToFit. That is what you stumbled upon in your next comment.
Sorry, I'm still a little slow and bit manipulation was never my strong suite - would taking 12 bits from x and y and 4 bits from i and k still lead to a 32bit key? Since that's the format Roaring consumes...

- Index::add: It seems this operation relies on the order in which the keys are added, and that order does not work well with either DF's feature shells or an efficient processing of world tiles without feature shells (unless there's some way to move directly from the last world tile of a row to the first world tile of the next one). A comment explaining what's special with 511 would be useful: I can't figure it out.
As said above if the keys don't come in strictly ascending order helping Roaring by calling runOptimize and shrinkToFit improves the memory consumption during the survey/index phase.
511 seemed to be the offset from last position the previous 16*16 mid_level_tile survey run (i = 15 and k = 15) to the position of the current  (i = 0 and k = 0) if y is odd - which is wrong and already removed from the code - but bear with me for another moment
Correct me if I'm wrong, but to efficiently process feature shells the iteration goes like this:
Code: [Select]
x=0,y=0              => x++                 x=15,y=0
>----->------>----->---->----->---->---->----
                                            ↓ y + 1
x=0,y=1              <= x--                 x=15,y=1
-----<------<-----<----<-----<----<----<----<
↓ y + 1
x=0,y=2              => x++                 x=15,y=2
>----->------>----->---->----->---->---->----
....
So every other/odd row is being processed "backwards", in descending x order, right?
.... I just added the x,y,i,k coordinates to the output of the keys_in_order data... now I really understand what you meant when you said:
...
Also of importance is that the movement pattern is complicated enough as it is (it took me a fair while to get it to work correctly).
...

Boy oh boy!  :o The iteration spans 4 feature shells in large worlds before the movement pattern repeats, wow! Mad respect for that!
Anyway this feeds Roaring a lot out of order keys which can lead to temporary sub-optimal behavior memory-wise.
I'll have to look into ways of mitigating that. This might take the form of an option for the user: Fast search which consumes more memory temporarily until the end of the survey/index phase or slow search that optimizes/"defrags" often and thus needs less RAM.

- Index::add: I'd change the code checking for duplicate keys to a one liner (which I usually avoid) and comment outthe whole line when not used, rather than just the output. The compiler will have to perform the function call unless it can somehow deduce it doesn't have side effects even if there's nothing to do when true.
Again that's just an debugging artifact that helped me to get a better understanding of what happened - so yeah that can & will be removed.

- Index::add: Is there a reason for the omission of code inside the candy check? The later storage of level?
Yes exactly, the empty block is already removed in my current working copy.

- Index::add: I'm not sure what you're after with the (explicitly redundant) checks for various layer materials (not sure if it covers veins). If activated, it would exclude gems, for instance, and regardless, if someone has hacked in something, I don't see why it should be filtered out (And I just realized someone hacking in steel as a layer would get it filtered out if all inorganics were merged, but the issue would still be isolated to metals, and it would be possible to handle metals only separately).
You mean
Code: [Select]
world->raws.inorganics[mineralIndex]->flags.is_set(df::inorganic_flags::SEDIMENTARY) ||
world->raws.inorganics[mineralIndex]->flags.is_set(df::inorganic_flags::IGNEOUS_EXTRUSIVE) ||
world->raws.inorganics[mineralIndex]->flags.is_set(df::inorganic_flags::IGNEOUS_INTRUSIVE) ||
world->raws.inorganics[mineralIndex]->flags.is_set(df::inorganic_flags::METAMORPHIC) ||
world->raws.inorganics[mineralIndex]->flags.is_set(df::inorganic_flags::SOIL)
?
Those I took from embark_assist::finder_ui::ui_setup (case fields::mineral_1) - once the inorganics are merged into one vector it can be dropped for sure - saying that when I experimented without this "filter" I got indices that had different names but the same content, for example galena and lead or garnierite and nickel - are those the pairings of the mineral containing a metal and the metal?

Ok, that was a lot - thanks again for taking the time to look into this very preliminary version of the code!
And for reading this wall of text till here :D
Now one more question: Is there a river size field in the DF structures on the level of embark tiles?
Or is it the same for all embark tiles of a region?

What happened in the meantime?
I spend quite some time obsessing over the performance and the memory consumption of the index.
Memory-wise I can say the current scope of the index (still missing some fields of the finder) is around 30MB serialized for a 257*257 region.
How much it actually consumes living in the RAM still eludes me - as the memory profiling does not work properly. This is complicated by the fact that an index created at run-time with out of order keys seems to be bigger than the same index that has been reloaded from serialized data - but I'll get there.
The standalone tests suggest that indexing during the survey/index phase shouldn't be a concern performance-wise, but I'll do integrated runtime checks just to be sure.

My next steps are roughly as follows:
- experiment with a variant of Index::add that takes the whole 16 x 16 mid_level_tiles at once instead of 1 mid_level_tile at a time.
- implementing the missing fields/indices (biome river_size, river_elevation, bad weather and effects,...), excluding incursions for now - I'll probably have some questions about some of those - but in essence some steps that currently reside in the matcher will have move into the survey, continuous numerical fields will either live in a vector (e.g. temperature) or probably in a map-like structure if not every embark tile has/needs them (e.g. river_elevation). Getting most or all of them will allow me to make an informed decision if the memory consumption is still tolerable. Having an analogue to the region might be a way to mitigate the memory costs for all attributes that are the same for all embark tiles with the same x/y.
- get queries running - I have a pretty clear idea of how to do that so that it performs good or even excellent in most cases. If the results aren't fast this will be a deal-breaker. The first version of this will run the query phase only after the survey/index phase have finished. (yeah I know, user feedback and responsiveness :-[) That way I hope to avoid all kinds of problems I might need to solve later. But the second iteration could run as soon as one region is completely indexed. The third iteration - well see the next point.
- get the incursions in there - I think this will integrate nicely with the concept of the indexing, but I'll have questions for sure. Adding incursions complicates running queries during the survey phase, but I'm have a low priority mental process working in the background on how to know when all relevant neighbors of a region tile have been processed. Solving that would allow for a third iteration of the queries, that could produce results during the survey phase that are "incursion-ready".
- as an optional feature: currently I save the indices to disk for debugging and performance tests - but seeing how easy it is it might be a nice option to allow the users to reload the indices (automatically) on a subsequent load of the world map and allowing for fast searches right away. Adding a version hash would make it possible to tell if the data is compatible with the code. What do you think? Even automatically creating the indices in batch mode might be an option.

Currently I (still) think it is feasible to move all information into the index and thus having pure queries during the search phase, which will avoid any additional iterations/calculations on the level of the embark tiles. But I'm willing to compromise on that if there are cases that lead to enormous, unproportional memory requirements or to hacky code (using an index-hammer on an algorithm-screw).
Also I haven't forgotten about your remark concerning the following possibility
I've been thinking, and believe it's a mistake to try to massage the current inorganics presence storage. All you really NEED is two bytes to store the first and last layer of the geo biome present for each MLT (in addition to the index of the geo biome itself, which is currently stored), as all the rest of the info is available from the geo biome itself (And since the two values are in the range 0-15, you can actually store both of them in a single byte). To get the first/last layers we could cut away a fair bit of the code from the modified Prospector code of the MLT processing (the removed code would still be needed elsewhere to extract the actual inorganics, though).
With that basic information stored, you can either process the geo biome each time you need the data, or you can try to pre process the geo biomes to speed up the information extraction.
- The layers potentially worn away by erosion are all soil layers, and DF never seems to generate more than 4 of those. It's possible to hack the geo biome to get more soil layers and/or deeper soil, and DF can erode up to 10 Z levels, if I remember correctly. The suggestion below doesn't actually make any use of this info, though.
- DF doesn't use more than 16 layers of the geo biome even if hacking has added more (DF stretches the last one to fill the gap to the magma sea if needed).
This means that one possible approach would be to make a bit array for each layer of each geo biome and then merge the ones you have in each MLT with OR operations (16 layers * 33 byte bit array * X geo biomes). Even if DF doesn't croak at a silly max size PSV world with a checkerboard layout (forcing each world tile to get its own geo biome), you'd still not use more than 35 MB to store the info in a more convenient format than the geo biomes themselves.

Okay, sleep. now.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 30, 2019, 05:23:44 am
- 12 + 12 + 4 + 4 = 32, so that would result in a 32 bit key.
- Yes, that's what the search pattern looks like. It's sort of fractal in that the processing order between feature shells mimics the one within them (the order within world tiles doesn't have any movement cost restrictions, and thus is done in a more human oriented line by line order). I think it would be possible to get the key generation code to mimic it, i.e. to get keys generated in sequential order, but it would probably take a number of attempts to debug it (on the other hand testing would be simple: just indicate a failure if the next key isn't the previous one plus one). This is probably a case where the effort should be on the coder (i.e. you) rather than on the user...
- When it comes to the checks for flags, you've failed to take the two first lines in the block into your copy. I have to admit I don't remember why I did it that way, but looking at it (without researching it), it looks like the code selects:
  - Things that are present in specific environments (probably to catch the elusive Alluvial ones)
  - Things that are present inside specific materials
  - Things that are layer materials.
- The plugin code looks at ores and finds the metals those can produce, so yes, a metal ore will result in the adding of the ore to the mineral vector and the metal(s) to the metal one. This is the case where there'd be some trouble if raw editing adds a metal as a layer material, as you could then get an entry in the common vector from both paths. Note that DF itself distinguishes between native gold (the ore) and gold (the extracted metal). It wouldn't be unreasonable for the plugin to require raw editors to respect this logic if they expect the plugin to work correctly (but it still shouldn't crash).
- River size: The river structure contains a list of all world tiles the river flows through, and each of those has a "flow" field for the volume of water the river carries, and there's a logic for how that is translated into stream, minor, etc. (this is documented in the XML, but is obviously in the plugin code as well). In addition to this, DF translates the flow into an in-game tile width that's stored in the MLT structure as x_min/x_max and/or y_min/y_max for entry and/or exit points along the edges. However, there's no need to use this in the plugin. On top if this the world tile data (region_map, if I remember the name correctly) has a flag to indicate that a river is a brook (i.e. can be walked on top) or a stream. Hacking can provide wide brooks, but DF only generates them when the flow is 0, if I remember correctly. Rivers follow the geography (Toady mentioned it in a talk recently) and presumably doesn't interact with regions beyond some internal DF calculation to compute how world tiles (and their biome parameters: at least rainfall, and probably drainage) contribute to the river's flow, and one region can be crossed by quite a few rivers. Oh, wait a minute: does the question about "region" refer to the world tile, rather than the regions in the DF structures? If it does, I'd suggest a change of terminology to avoid confusion.
- The current data structure has one level of data collected/summarized at the world tile level to allow for an early weeding out of world tiles that cannot have matching embarks. Info that is common for all MLTs ought to be stored there, if it's missing from there. Thus, I think the level you're looking for exists already.
- I'd be hesitant about saving matches to disk for later use for a number of reasons:
  - The disk would get cluttered with index files that would have to be removed manually.
  - The next DF version will have spreading evil. This will invalidate Evilness indexing in worlds where a fortress has been retired after a few decades.
   - There are tools for the current version that allows you to modify the world pre embark, invalidating index file contents in various ways.
  Thus, I'd check the label of this can of worms very carefully before determining they're tasty enough to open it...
- I don't know whether storing everything in indices (with the attendant lookup) is going to be faster than accessing pre processed geo biome info using first/last layer as the key pair. I do know it's going to require more memory, but I don't know the answer to the crucial question of whether it's going to require too much memory. The key gain with either approach is that you'd have to scan the world only once.
- Incursion handling with the index approach ought to be handled such that the relevant incursion info is integrated into the info for the MLT, i.e. it should be possible to store that the MLT has evil, neutral, AND good in it, for instance, that it has a partial aquifer coverage, and that it contains biome X, Y and Z. As far as I understand this isn't hard to do: all it would require is a few adjustments, but most of it seems to be ready for that (If I understand the indexing correctly, there's nothing blocking the current structure from adding the key for an MLT in more than one of the evilness indices, for instance).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 30, 2019, 05:31:16 pm
- 12 + 12 + 4 + 4 = 32, so that would result in a 32 bit key.
That seems easy enough ;D I got 32 as a result too when adding those values, but wanted to be sure that i understood correctly.
Would that operation be reversible, meaning could x,y,i and k be extracted from the resulting key again?
That is a requirement of the current design, to allow the creation of the proper embark_assist::defs::match_results later on - that requirement would be relevant for the next point as well.

... I think it would be possible to get the key generation code to mimic it, i.e. to get keys generated in sequential order, but it would probably take a number of attempts to debug it (on the other hand testing would be simple: just indicate a failure if the next key isn't the previous one plus one). This is probably a case where the effort should be on the coder (i.e. you) rather than on the user...
That's a fascinating idea! A key iterator, that generates the key values analogue to the movement pattern of the iterator of the world tiles - hm, never would have thought about that one.
I'll have to let this one simmer for a while. It would be an optimization anyway. Did you create something like that before? And of course it would need to be reversible.

- When it comes to the checks for flags, you've failed to take the two first lines in the block into your copy.
I did, didn't I... I fixed that. But the duplicated index contents (galena and lead ...) happened when I deactivated the filter altogether. No filtering would probably be true for a merged inorganics vector as well. So that's something to consider when doing that.
Also I would prefer not force modders/raw editors to do things in a certain way. But first things first - get it running, then have some test cases that might crash it or not...
First I'll keep 3 separate vectors just to avoid any new funny, confusing errors...

- River size: ...
Oh, wait a minute: does the question about "region" refer to the world tile, rather than the regions in the DF structures? If it does, I'd suggest a change of terminology to avoid confusion.
Yes, you are right - I'm currently very code-centric and was talking about region_tile_datum and the level of processing of those tiles. I'm aware of survey_rivers in survey.cpp and was wondering if the river size or something analogue is also available on the level of embark tiles (mid_level_tile) in the structures of details->rivers_horizontal/vertical. Or if the river_size of a region_tile_datum automatically is the same for all related mid_level_tile that have a river and they inherit it from their "parent" region_tile_datum?

- The current data structure has one level of data collected/summarized at the world tile level to allow for an early weeding out of world tiles that cannot have matching embarks. Info that is common for all MLTs ought to be stored there, if it's missing from there. Thus, I think the level you're looking for exists already.
Again, you mean region_tile_datum, don't you? If they can be addressed/found/iterated fast and easily during the matching/query phase then yes they would be the right place. Actually I'm not sure anymore why I thought there might be the need for a new structure on the same level as region_tile_datum - perhaps it will come back to me...

- I'd be hesitant about saving matches to disk for later use for a number of reasons:
That are really some tasty worms you got there!
Disk storage and clutter: I was thinking about storing the index within the safe-folder, which might mitigate the cluttering of orphaned/derelict index files.
Spreading evil: I thought about indexing cities and neighbors which can change over time(- can they?) - for that adding the current year to the index folder would help knowing if all mutable indices have to be rebuild. That would be true for spreading evil as well.
Tools to change a world pre embark: You are evil :D I - ah well - that is a real doozy.
I see your point here, I really do - but I feel it might add value to the plugin if the user has at least the choice to reuse the indices and thus does not have to spend another 5 to 10 minutes waiting the next time... but this is nothing that has to be decided now...

- I don't know whether storing everything in indices (with the attendant lookup) is going to be faster than accessing pre processed geo biome info using first/last layer as the key pair. I do know it's going to require more memory, but I don't know the answer to the crucial question of whether it's going to require too much memory. The key gain with either approach is that you'd have to scan the world only once.
Me neither, and yes, that key gain is what I'm after - perhaps those to approaches can be combined - again an possible optimization for when it works, that's pretty much what I wanted to say.

- Incursion handling with the index approach ought to be handled such that the relevant incursion info is integrated into the info for the MLT, i.e. it should be possible to store that the MLT has evil, neutral, AND good in it, for instance, that it has a partial aquifer coverage, and that it contains biome X, Y and Z. As far as I understand this isn't hard to do: all it would require is a few adjustments, but most of it seems to be ready for that (If I understand the indexing correctly, there's nothing blocking the current structure from adding the key for an MLT in more than one of the evilness indices, for instance).
Storing the same key in different indices is absolutely no problem, also a query (e.g. find a MLT with a evil biome) would be fine with it, as it does not care about the fact, that the same key is in more than one complementary index. Moving all incursion information into the MLT would be the most elegant way for sure. But right now/at the beginning I could live with a solution that handled incursions as a special case, that gets processed later on when the neighboring MLT that belongs to the adjacent region_tile_datum is being surveyed - that's how I imagine it anyway - does that match the current way of it is done? (hehe, starting with the questions about incursion already).

Okay, tomorrow I might get to program again and break some more things - today there wasn't any time, but I really wanted to clarify some of my muddled thoughts.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 01, 2019, 04:53:09 am
Building and extracting the parts from a key that's the added up like that the 32 bit one I suggested is rather trivial:
Build: Shift X 18 steps + Y shifted 8 steps + i shifted 4 steps + k (where shift can be replaced by multiplication by 4096 * 8, etc.: I don't know if the compiler would be smart enough to realize that multiplications by constant powers of 2 can be replaced by shifts, but C is sufficiently close to assembly to have explicit shift operations).
Extract: You'd shift in the other direction and then mask out the extra bits at the top with an AND mask (or mask out the bits you don't want and then shift: the order doesn't matter).

I haven't created a key matching the movement pattern (or anything like it), but it's certainly possible (the movement pattern encodes the logic in a convoluted way, but it would have to be teased out). The logic is certainly reversible (there's a 1:1 correspondence between coordinates and keys within the valid key range), although, again, it would require some work to get it right (or the right mind to handle that kind of problem, but it's not a mind I have).

Since galena is an ore that produces both lead and silver (according to the wiki), the metal extraction checks would mark lead and silver as metals that are present.
I think it's a wise approach to get things to work first and optimize later. It is rather useless for something that's blindingly fast, but doesn't work...

The reason it's called region_tile_datum is that I used to call the 16 * 16 embark tile area "region" (hence region manipulator), until realizing DF calls the middle pre embark map "region", and before Toady said, in some FotF response, that he'd called the tiles within a world tile Mid Level Tiles, so it's a historical inaccuracy where I partially, but not completely, reworked the naming.
  If I recall correctly, different MLTs do not have to have the same river width: if a river changes width the change is gradual, i.e. the change is widening or narrowing over several MLTs if needed. There's also the case of joining rivers: they can be of a different width (DF does never generate two rivers within the same world tile as far as I've seen, but joining is implicit from the entry points along the world tiles' edges).
  The argument above shows that the current river width logic isn't fully correct, as it uses the world tile width (as stored in the river structure) is used for all MLTs with rivers on them, rather than actually measuring the width(s) for each MLT. I don't think that's serious enough to require fixing immediately, though.
  The data you're looking for on the MLT level is the x_max - x_min and y_max - y_min values that show the actual width in in-game tiles, which would have to be translated back to river size (I think the XML comment contains that info, but I don't quite remember. If it doesn't it shouldn't be too hard to investigate it by hacking flows at the flow change points and embarking to check the river widths).

Yes, the world_tile_data is a vector of vectors of region_tile_datum elements, and so is easily accessed via (x, y) coordinates.

Cities and neighbors aren't used by the plugin... I've made an attempt to determine neighbors (there's a thread about that), and the "final" resulting script seems to work, but there are still unknown factors at play, so the data isn't good enough for "real" use.
Neighbors can definitely change over time as sites are conquered and razed, though.
  Currently Savagery changes over (a long) time: I've had worlds where I've located good embark locations (Savage) with a short history and then regenerated from the same seeds with my actual desired history length only to find the location Savagery has been reduced (and it's known civs can "tame" savage areas to make it possible to settle in them).
The only factors I know change over time are Savagery and (soon) Evilness. There's no indications any of the others change, as far as I know (erosion applies only to world gen itself, not the history, for example.
  The mother of all pre embark modification (and just about any other modification) is gui/gm-editor, and I didn't write that gem. I won't really accept the description of "evil", but "devious" could be accepted...
  I'm not sure people would embark/search for embarks in many sessions in the same work that often, but if proper warnings about its use are provided it could be of some use. Regenerating the Evilness/Savagery data is rather easy, as that's stored at the world tile level, so you don't actually need to read the MLTs to apply it (assuming you've stored the info of which world tiles provide the biomes of each MLT).

I'm not really happy about the half assed way incursions are handled currently. To do it properly, you really need to process the world twice: first to extract the "primary" MLT info, and then to add the relevant parts from neighboring MLTs that provide incursions. This is done on the first pass for all the fully interior MLTs, but the ones at the edges are processed only if their neighboring world tile MLTs have been processed, and there's currently no second pass to process those: that's done when/if a second search is made. If all the relevant MLT info is stored (rather than generated and discarded) it would be possible to do the task in two distinct passes, i.e. first gather primary MLT info and then a second pass to apply incursions. There's a UI issue with how to display progress, though. Possibly yellow X->light green X-> green X.

Edit: I think I've managed to cobble together functions to generate a key/extract indices from a key. The script tests that the parameters fed to the key generator matches those returned from the index extractor, but it hasn't been tested to see if it actually manages to follow the survey pattern, only what I think the survey pattern is. Also, I haven't verified that the keys generated actually are within the expected value range.

Spoiler (click to show/hide)
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 09, 2019, 04:25:52 pm
I'm back, from some more germ SCIENCE real life felt it needed to test on me...
Hope that's it for a while with the experiments :)

Anyway - thanks for the key-position-script.
I'll try to incorporate it in the next session, whenever that will be.
But I uploaded one of my output files here
http://ul.to/242ekbya (beware: 556 MB unzipped!)
that should allow you to verify that the world tiles are being surveyed in the order you would expect.
When I drew the schematic of the iteration on November 29, it seemed to me that it always first went the long way in the x direction and then one step in the y direction.
That no longer seems to be the case, it seems the other way around now - there were multiple small errors in the way I decoded the naive key - which might have added up to that.
By now I process all 256 embark tiles within one loop, which helps speed things up (batching/buffering the adding to the indices), also it allows for an easier way to generate the keys - I adapt your script once I'm there...

Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 17, 2019, 05:13:19 pm
So I found the time to do some tests with the key generation that follows the iteration pattern of the survey.
Following a sample of x,y,i,k positions (only the first and last of each x-y-group) and the associated key in CSV format that also contains a marker if the key is not continuous:
Spoiler (click to show/hide)
You can see, that as soon as the second column (x = 1) is being processed there is a difference in the next key value (8448) of 4352 to the expected value of 4096.

I played around with my adaptation of your script a little but haven't had any epiphany till now. It also could be an error in the c++ implementation - do you see any (obvious) errors:
Spoiler (click to show/hide)

Apart from that it seems that the more coherent/continuous keys already resulted in an slightly faster (~10%) adding of the keys to the indices - but I'll have to verify that.
Next up: Queries.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 18, 2019, 08:34:40 am
Yes, my logic is incorrect. The feature shell is its own little box of a 16 * 16 * 16 * 16 = 64 kB block (when complete: the edges typically consist of a single row and/or column), so the feature shell part of x and the local part of x have to be treated separately, and the feature shell part of y similarly has to be split from the local part.
Back to the drawing board...
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 18, 2019, 10:11:48 am
I just double checked and noticed that the value of the difference/discontinuity always is 4352 (which is 17 * 256 itself - that seems significant somehow), at least while iterating through the feature shell and for a world with a given size of 33x33 - for worlds with other dimensions the constant is likely to have another value.
Okay, tested it for a 257x257 world: The constant offset is 61696 - which is 241 * 256. Where 241 is (257 - 16) - the total dimension of the world minus the width/height of a feature shell...
Does that help?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 18, 2019, 11:15:49 am
I'm still on the drawing board, but have a first draft for the key generation (haven't run it yet, and have yet to start tackling the reverse direction, but it should be possible to decompose the sum into its 3 parts, and from there into the original parameters).
Basically the "new" logic is:
- Sum up all the indices in the feature shell rows prior to the current row.
- Sum up all the indices in the feature shells prior to the current one in the current row, taking feature shell processing direction into account, as well as whether it's a complete shell or a last, reduced size, one (and if going right to left the first shell is narrower than the rest).
- sum up all the indices in the currently processed feature shell, accounting for all the complications.

The key should be the sum of the three parts.

Unfortunately the observations don't help much, as the logic was fundamentally flawed in that it tried to generate indices based on the row length while inside a feature shell, which is plain wrong.

Edit: OK, I've finally managed to get a new version of the key/indices generation logic. Again, I haven't tested it against the real code, so it may still use an incorrect algorithm, although I'm reasonably confident it matches what I think it is.

Spoiler (click to show/hide)

P.S. The script contains a number of constant declarations within the functions. These constants ought to be declared outside of them.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 21, 2019, 06:48:54 pm
Thank you for the new version of the script - I'll integrate it as soon as I have finished some more query-tests:
I've thrown together a very basic but working query-plan system and successfully found a volcano in a aquifer zone within a small world, with the same matches as the existing matcher.
It's a very small test case but if everything scales as I think it should it will be as fast as I hoped. Now for the assiduity/drudgery of adding all missing queries related to all the already implemented indices.
And adding all missing indices - which might get interesting. And then adding all those queries...  :o
During this step I'll also test with a big world and less special criteria to see how it behaves performance wise. Probably I'll run the same test described above with a big world tomorrow, just to be sure.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 22, 2019, 04:58:27 pm
Just a quick update: Works just as fine when searching for a volcano in an aquifer zone within a 257x257 world.
Happy holidays - if those apply to you :)
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 23, 2019, 04:54:02 pm
Merry Christmas to you too (I'm allergic to Political Correctness).

Good to hear the sanity check worked as intended.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 03, 2020, 05:38:28 pm
Happy New Year!
Also: Good news everyone!

I just ran a test case for a big world with
evilness = neutral (# of embark tiles: 16.758.830),
metal_1 = silver (# of embark tiles: 16.423.370) and
metal_2 = copper (# of embark tiles: 15.411.174).
This is pretty close to the worst case possible in my test world (total # of embark tiles: 16.908.544). First I was a little shocked - it took more than 15 minutes to complete.
But then I realized that many embark candidates got checked more than once. After adding a check for that it just took about 50 seconds.
That is not as fast as I originally had hoped but still much faster than the current solution during a subsequent search for such broad terms.
For more limited searches it is a lot faster - the speed is proportional to the criteria with the fewest hits/manifestations in the world.
Next up: Integration and testing of the revised key generation.

Oh and: I think I found an edge-case one-off error in the original matching. When comparing the matches produced by it with those found by the new code there sometimes was 1 additional row/column that seemed correct on visual inspection. It seems to be related to embarks that would contain embark tiles, that have i/k = 0 or 15.
Following an example (at x:168 y:122 i:1 to 6 k:10) within the region here http://dffd.bay12games.com/file.php?id=14584
Searching for a 6x6 embark with aquifer: present and min_magma: Volcano
Spoiler (click to show/hide)
All affected embark tiles in that world
Spoiler (click to show/hide)

Or am I mistaken?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 04, 2020, 06:28:11 am
Happy New Year to you too!

I think you've seen the unfortunate effect of incursion handling. The first search excludes the edge tiles because they don't have the required info from the neighbor tiles in the next world tile available. The second pass is capable of making use of the info as it's been generated at that time.
However, if your storage works out as well as it sounds like, it should be possible to perform the job in this sequence:
1. Scan the world tiles, marking potential world tiles.
2. Scan all MLTs and produce preliminary MLT results.
3. Apply incursion effects to all MLTs and produce definite results.

For subsequent scans the steps would be:
1. Scan world tile data to mark potential world tiles.
2. Match MLTs. It may well be that this step can't produce any useful progress indication because the matching isn't performed in sequence, if I understand it correctly. However, it might still result in a "random" change of candidate world tiles into confirmed world tiles, with a final wipe of those that didn't get any matches.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 05, 2020, 06:41:45 pm
Ah, I see - yes, that is what's happening.

I've integrated the revised creation of ids/keys and they are completely continuous, thanks again for that!
This also seems to speed up the indexing by 20% to 25% (compared to my naive id generation).
Now I'll have to find a way to balance to need for index optimization (which creates run-containers and shrinks the indices) during indexing with the time it takes: Letting it run with unoptimized indices is faster but eats up more memory. Optimizing frequently makes it slower but reduced the max memory footprint. I might get away with a optimization after every feature shell and only process those indices that actually changed since the last optimization - there are some experiments needed here.

To make a qualified statement about the possible steps for the final integration of the index-query-structure (that also needs to be more iterative/update-tick-friendly instead of ignoring the allotted delta-time) I'll have to better understand the incursion mechanic - I'll hopefully find the time during the next days to describe my current understanding/mental image to you to see if it is correct.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 12, 2020, 05:47:16 pm
Ok, I took another look at the incursion comment here https://github.com/DFHack/df-structures/blob/4388fbfb8f51be41777406c6e7c518f738c195c7/df.world-data.xml#L376
and also in the code of matcher (process_embark_incursion_mid_level_tile, process_embark_incursion) and survey (process_embark_incursion_mid_level_tile, survey_mid_level_tile + translate_corner) and it left me smiling confused.

So let us play a game of hot/cold or true/false.
I'll postulate some ideas/theories of mine (some of which might contradict others, as alternatives to real questions) on how I think incursions work and you initially only confirm or reject those claims. In a second step we can go into the details. Also I'll update this post to add more claims so that all of them are in one place and also mark the cold/false ones as such.
Also feel free to post your own claims :)
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 12, 2020, 06:19:56 pm
1. Correct.
2. Correct.
3. Correct. But the blasted data still indicates that should happen, i.e. it isn't sanitized to only indicate the legal cases, so is has to be checked before being applied, and we have to go through recovery processes to determine what should happen then.
4. Correct.
5/6. Basically correct. The data structure specifies in which direction an incursion should go, so e.g. at the middle of the north side of a tile, there is either an incursion into the tile above, or an incursion from the tile above into the tile (with the exception of the edges of the world, of course, where there's always always a straight edge). Similarly for the corners: one of the 4 tiles incurs into the other 3. Thus, the logic couples the tiles together in dependencies for each edge/corner.
The data for incursions reside in its own structure beside the others.
7. The incursion control data structure elements "belong" to the north and west sides of the tiles respectively, as well as the NW corner of them.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 13, 2020, 01:02:42 pm
Ok, I updated the post by adding 7.
And to be sure there is no misconception on my side I added 8. as differentiation to 1. and 2.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 13, 2020, 04:59:07 pm
8: Correct. The restrictions are in that you can't receive from non existent tiles (i.e. outside of the map), every "receiver" is matched by a "giver" in the corresponding neighboring tile (corners has one "giver" and 3 "receivers"), and there is no "neutral" choice: there is an intrusion in one direction or the other.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 17, 2020, 06:00:07 pm
Ok, .... that is a lot of incursions :o which really might be the killer for this whole endeavor... As I originally thought incursions only happen at the edges/corners of world tiles.
We'll see.

I had another look at https://github.com/DFHack/df-structures/blob/4388fbfb8f51be41777406c6e7c518f738c195c7/df.world-data.xml#L376 (https://github.com/DFHack/df-structures/blob/4388fbfb8f51be41777406c6e7c518f738c195c7/df.world-data.xml#L376)
and in connection with 8. I'm wondering: Is it sufficient to process the "giver", knowing where its data is going or is it necessary also to look at the receiving side as well?
Or to put it differently: Does the "giver" have enough data to determine where and what is passed on to the 1/3 "receivers"? And are the following rules
Quote from: PatrikLundell
There are also certain rules forcing ocean/lake biomes to lose edges to mountains, and both of them to anything else, no matter what the original array value is.
mentioned in the comment on the world-data structure already "encoded" in the data or do we have process them ourselves?

If processing the "giver" is sufficient all internal and all outgoing incursions of a world tile can be processed when the world tile is being visited during the survey phase.
All incoming incursions from neighbors could be processed during the first and sole visit of those neighboring world tiles during the survey phase.
And embark matching could be delayed until the world tile and all of its neighbors have been surveyed:
After surveying a world tile one could increment a surveyed_neighbors_counter of every neighbor and when it reaches 3/5/8 (depending on the position of the neighbor => world corner, world edge or "inside") all relevant data is present so that matching of that world tile can be processed. That would result in a short delay of match processing for most world tiles, only those living at the edge of their feature shell might have to wait till the next row of features shells is being surveyed.

If we need to look at both, "giver" and "receiver" ah - I'll have to let this one simmer a little longer, good ideas take some time and looking the other way.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 18, 2020, 01:20:44 pm
The "giver" has all the info on what's given, so if all the info is available, it's possible to do the incursion processing when needed, rather than up front.

Unfortunately, DF does not adjust the incursion data to match the incursion direction that actually takes effect in the exception cases, (world edges, lakes, oceans, mountains), so they have to be calculated (and in the case of corners you'll basically have to look at all 4 tiles for that).

You can't process all incursions in a single pass, because neighboring world tiles will have to be processed one before the other, and both will typically produce incursions into the other one, unless the processing allows incursions to be introduced before the "real" data for an MLT is introduced. Also, you can't just merge things together as you go, as that would cause incursion info into a tile to be propagated into further tiles as part of the "real" data for that tile. Essentially you have to keep the "real" data separated from the compound info until the "real" data is no longer needed for any further incursions. This can be done with temporary structures for the "real" data that's discarded when all the merging has been done, for instance.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 19, 2020, 04:03:11 am
A new DFHack version has been released. This also means all changes made to this plugin since the last release are released as well.
I'll try to remember what has been done over this period...
Improvements:
- Incursions. This is the big change. And "incursion" is a piece of a neighboring tile's biome that juts into the current tile, allowing for a single Mid Level Tile to host more than one biome, with its attendant features (aquifer, evilness, etc.). Thus, a single MLT can have a partial aquifer, both Evil and Good alignment parts, multiple biomes, etc. The detection logic makes use of incursions where it's deemed to make sense, so e.g. mineral presence does not make use of incursions, as the amount of the minerals would be rather small, and probably disappointing.
Incursion handling has resulted in some unfortunate compromises, however, as the logic can't apply them properly to the MLT's at the borders of world tiles due to mutual processing dependencies, so the first search does not match any embarks including tiles from world tile borders: a second search is required to catch those.
- Waterfall detection searches now allow for searches for falls of given number of Z levels, rather than just presence.
- Evil weather has been added to the pre embark information.
- Added an optional "fileresult" parameter for crude external harness automated matching support. If the parameter is present on the command line when the plugin is activated the search profile stored to file is read and a search using those parameters is started and repeated once to account for incursions as well. Thereafter the number of world tiles containing matches is written to the file <DF>/data/init/embark_assistant_fileresult.txt. This file is deleted before the first search is started, which allows for an external harness to detect the removal of the file, indicating the start of the search, and the creation of the file, indicating its end.
Note that the author cannot provide any assistance when it comes to harnesses due to a lack of knowledge.
- The world tile movement logic has been improved, speeding up subsequent searches substantially.

Bugs fixed:
- A bug caused a crash on worlds without generated metals. This has been fixed (as well as the implementation doing what it was supposed to do).
- A bug caused mineral matching to fail to cut off at the magma sea (a flaw that DF's integrated search has as well). This has been fixed.
- A bug causing about half of the river tiles to be missed has been fixed. This also affected waterfall detection.
- A bug, or rather failure to understand and take the weird way DF implements rivers into account caused a fair number of river tiles to be missed (also affecting waterfalls). This has been fixed.

I generally avoid double posting, preferring to adding "Edit" sections to the existing post, but the contents of this post doesn't have much in common with the previous one.
Title: Re: DFHack plugin embark-assistant
Post by: clinodev on January 19, 2020, 04:43:24 am
Thank you for all your work on this project!
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 19, 2020, 05:20:51 pm
A new DFHack version has been released. This also means all changes made to this plugin since the last release are released as well.
I'll try to remember what has been done over this period...
Splendid!

Being nitpicky I know, but there was also the bug triggered by pocket worlds:
Thanks for the crash report.

It took a bit of time to find out what was wrong, but it is indeed a bug.
The line should be
Code: [Select]
            tile->region_type[i][k] = world_data->regions[tile->biome_index[mlt->at(i).at(k).biome_offset]]->type;
i.e. "biome" -> "biome_index".
The reason it crashes only on pocket worlds is that the number of regions in those worlds tend to be fewer than the number of biome types, i.e. the index passed in was the biome type, but was interpreted as the index of the region.
The bug should screw up the reasonably (I think) uncommon searches for region types when it doesn't cause a crash.

Also thank you for your fast answer concerning incursions.
I'll have to do some more code reading and stepping through the code during survey and matching phase in a small world to get a better grasp of the details.
What I can say is this: The index structure actually would allow for storing data of an incursion from a neighbor before the receiving MLT was being surveyed, all that is needed is the correct key, that can be calculated - thanks to you - but it might be rather complicated to get rid of those if they are an ocean/mountain and the receiving MLT is e.g. a desert.
This also results in a question: Does the following sentence only mean that the biome won't be transferred or does it also include all other features (aquifer...).
Quote
There are also certain rules forcing ocean/lake biomes to lose edges to mountains, and both of them to anything else, no matter what the original array value is.
If this includes the biome and all the features I would have to retain all this info for later, so it could be undone.
If this only refers to the biome it just could be removed if the receiving MLT has a "stronger" biome type.

Quote
Also, you can't just merge things together as you go, as that would cause incursion info into a tile to be propagated into further tiles as part of the "real" data for that tile.
Currently my design keeps the real source data (MLTs) separate from the index data (pure sink) during the survey phase - so any further propagation should not happen, but I'm wondering, how could further propagation happen if always 2 tiles (with the exception of corners) are being linked as you said here
Quote
every "receiver" is matched by a "giver" in the corresponding neighboring tile (corners has one "giver" and 3 "receivers"), and there is no "neutral" choice: there is an intrusion in one direction or the other.
Sorry if I should have understood/interpreted that wrong, which is quite likely. That would be just more evidence I need to see those rules and the data in the context of program execution.
Ah - I think I'm starting to understand: There are up to 8 incursion giver candidates (the neighbors of the MLT as corners and edges) for every MLT (exceptions world-corners and -edges...) but only 1 of them actually will be a giver, but the other 7 could be the giver to another MLT, which includes the winning candidate, which would lead to further propagation. Yes?

Again thanks for your patience!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 20, 2020, 05:24:38 am
Yes, the bug you reported was fixed as well, although I missed reporting it.

Incursions are packet deals, to the mountain etc. incursion inversion applies to everything. Instead of a mountain incursion into a steppe, we'd get a steppe incursion into the mountain, with all the associated data.

Hypothetical incursion contamination process:
- Survey World Tile A, and apply incursion information to border World Tile B MLTs that haven't been surveyed yet. As a result, some of these border MLTs may have info about containing biome A, B, and C (because it happened to receiving incursions both from the corners and the edge).
- Process World Tile B, where the edge tile above is identified to have a native biome D, so its biome set is now (A, B, C, D).
- Process incursions in World  Tile B, at which time we note that the problem MLT above makes incursions into two neighboring tiles, resulting in those tiles getting tagged with biome A, B, C, and D in addition to whatever biome it has natively, but the incursion actually contains only D.
The above also goes for other properties, such as e.g. aquifers.

You can't keep all the data from all MLTs in the world throughout the survey process, or you'd use up too much memory: you have to discard the data when the processing of it is done as you go. I've retained the border MLT info for incursion processing but discard the interior data when the processing of that world tile is finished. You'd have to do something similar, but can be more intelligent about it and discard the border data as it has been used for all relevant incursions.

It seems like you misunderstand the giver-receiver relationships. For a given (interior) MLT there are 4 edge incursions either going inwards or outwards so the tile can receive 0-4 incursions and perform 0-4 incursions, with the sum being exactly 4.
For each corner there is exactly one incursion provider and exactly 3 incursion receivers (all receiving from the same provider).
Thus, if you know the situation for one side of the arrangement, you also know the situation for all the other sides of that arrangement, which is why DF stores the info in a single place for each of these interface points. If the East side of an MLT received, that also means the West side of the MLT to the East gave.
There is no relation between different interface points (i.e. edges or corners) of an MLT. Each one of them is related only to the counterpart(s) for that interface point (which reside(s) in (a) different MLT(s)). Having an incursion in one place says absolutely nothing about the state of other edges/corners of the same MLT.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 26, 2020, 05:14:42 pm
Thank you for those explanations!

I did some more reading and are currently in the process of stepping through the code that handles the incursions - as part of that I created the following annotated call tree:
Code: [Select]
# matcher::embark_match
// tldr; does the actual matching for the current MLT and delegates the incursion processing for the outer edges of the embark rectangle as there is no need to process the inner part of the embark rectangle
// starting ~ line 773 the both north corners (NW+NE) and the north edge of every northern embark MLT of the embark area, then the south corners (SW+SE) and the south edge of every southern embark MLT are being processed
// starting ~ line 888 both west corners (NW+SW) and the west edge of every western embark MLT and then both east corners (NE+SE) and the east edge of every eastern embark MLT of the embark area are being processed
// the second loop respects all already processed corners, so no duplicate processing
    # survey::translate_corner/survey::translate_ns_edge/survey::translate_ew_edge
    // those 3 methods apply the rules described in world_region_details for edges.biome_corner/edges.biome_x/edges.biome_y to find the origin direction of the incursion to the current MLT corner/edge
    # matcher::process_embark_incursion_mid_level_tile
    // locates the correct incursion origin MLT + related RTD/world tile with the passed origin direction for further processing       
        # matcher::process_embark_incursion
        // actually processes the matching with the incursion data with the correct MLT and RTD/world tile

Is that basically correct?

And I'm wondering: Could it be, that in embark_assist::survey::translate_ew_edge instead of
Code: [Select]
biome_x
Code: [Select]
biome_y should be used at the following lines:
https://github.com/DFHack/dfhack/blob/82f082d7cbd6b823ab4c54d0dfbbf578f7fb1c4a/plugins/embark-assistant/survey.cpp#L1912
https://github.com/DFHack/dfhack/blob/82f082d7cbd6b823ab4c54d0dfbbf578f7fb1c4a/plugins/embark-assistant/survey.cpp#L1917
as the edges between east/west tiles run vertically/in y-direction?
Or am I getting something wrong here again?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 27, 2020, 02:21:08 am
It's a bit hard to follow your description as the line numbers are too approximate to allow me to be certain about what you refer to. However, I assume it's the section following "//  Take incursions into account." at line 731 in my copy of the code.

Yes. You don't have to process incursions in the interior of the embark rectangle, because those incursions will contain things that are already accounted for as part of the info for the MLTs they originate from.

Yes. The first loop deals with the top and bottom rows of the embark, failing to perform incursion handling on interface points whose neighbors haven't been surveyed yet (because they're in a different world tile that hasn't been surveyed).

Yes. The second loop does the same for the east and west edges.

Yes. The translate... figure out incursion directions with respect to the subject (the magic direction number parameter), taking complications (world borders, oceans, etc.) into account.

Don't understand what Return To Desktop means in this context...
Yes. process_embark_incursion_mid_level_tile just locates the correct incursion MLT and feeds it to process_embark_incursion, which performs the actual processing. It would have been possible to use a variable to store the pointer to the MLT and make a call at the end rather than perform the call directly in each MLT selection case, which would have resulted in fewer lines.

Yes, again. It's a bug, as you assumed. It should indeed use "y", not "x".


Title: Re: DFHack plugin embark-assistant
Post by: vjek on March 15, 2020, 09:58:03 am
Looking for a feature enhancement to this tool, here's the use case, briefly, with more details after:
- Dynamic population of a list of REGIONAL_ effects that can be selected for filters
- Application of these filters shown on the world map, same as the filters for flux, sand, biome, metal, and so on.

The goal of the change would be to allow players to find which REGIONAL_ interactions exist on what tiles.
Currently, effects such as blood rain, thralling, and re-animation are covered.  This would be an additional feature, but not quite so specific or static.

In advanced worldgen, when "Number of Regional Interaction Types" is set to a value (value of 10 shown in the spoiler), this number of REGIONAL_ values is created in: df.global.world.raws.interactions
If this list of REGIONAL_ values could be enumerated in a select-able list for embark filtering, this would allow players considerable flexibility in selecting which type of unique Regional Interaction they wanted to embark on.

It doesn't particularly matter where the list is enumerated in the UI.  It could go somewhere between Blood Rain and Reanimation in the list, perhaps with the heading/title: Interactions or Regional Interactions.
As a bonus, if, when traversing the list (similar to biome manipulator) it also showed the features of each Regional Interaction, then an informed decision could be made by the player regarding which one they wanted.  These REGIONAL_ values vary randomly by world, and are procedurally generated.

I think all the lists, arrays, etc and locations of them are known, and all the relevant code already exists in either survey.cpp or biomemanipulator.lua, currently.
Any questions for clarification, happy to oblige.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on March 15, 2020, 11:00:39 am
Unfortunately, that's tricky for a number of reasons:
- There's no telling what values a player may select for the number of regional interactions. It may well be in the thousands (the world I look at now has 11601 interactions, although most aren't regional, of course, but I wouldn't rule out hundreds or a few thousand).
- Second level selections (i.e. have an selection criterion expand) is not trivial. I've sort of worked around it for a future update by adding the dynamic entries at the end, but that trick can only be performed once. It's probably not impossible to implement a two level UI, but it has to be readable as well when contracted. However, the criterion "regional interaction has to be X" where the list is populated dynamically isn't that hard to implement (the set of minerals, for instance, is read from the raws section to allow for modded ones). However, finding out that you want REGIONAL_798 is better done using some other tool (such as the Biome Manipulator or, better, a new tool someone writes to mess with interactions).
- Interactions is a painful lot to deal with due to how messy they are (but there are people who like to get their hands dirty!), and it can be noted that the Biome Manipulator displays only a subset of the info (and there's a reason there's no functionality to change interactions themselves: it's possible to do, but would require a lot of UI, including understanding of additional parts).
- Also note that when you select a particular interaction you implicitly select a particular region (I think interactions can be shared, but if they can, it probably doesn't happen often), and that means you've got very little room for additional constraints on your embark. Thus, I think changing the world to match the desires is probably better than searching for a lucky hit in most cases.
- When it comes to the mapping of interactions, there's some new stuff that I don't think has been identified, but I suspect it doesn't affect regional interactions, at least not vanilla ones. Also note that I'm not sure how much the spreading evil thingie affects the logic. I think the logic is still the same, but there might be subtle changes that will cause the current logic to make incorrect evaluations.
Title: Re: DFHack plugin embark-assistant
Post by: vjek on March 15, 2020, 01:44:37 pm
Ok, so, say you've isolated that REGIONAL_4 is the regional interaction that you're interested in finding, to embark where it exists.
Manually (or otherwise), what structures would you need to iterate through to see if it's present in a given embark tile?
Presumably something in df.global.world.world_data ?  Or is it not present there, in a searchable form?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on March 15, 2020, 04:16:36 pm
You actually have to go via the interaction, and an interaction can only be tied to one region. Here's the relevant part from the Biome Manipulator:
Code: [Select]
    for i, interaction in ipairs (df.global.world.interaction_instances.all) do
      if interaction.region_index == region [Surface] then
        Weather_Page.Interaction_Index = interaction.interaction_id
        break
      end
    end

So, once you've found the region, you'll have to iterate through the list of world coordinates in the df.global.world.world_data.regions [interaction.interaction_index].

Going from an embark tile, you'd find the df.global.world.world_data.region_map [x]:_displace (y).region (or possibly region_id, I don't have the XML in front of me) and then iterate through the interaction_instances to find a match (or not, of course) for that id.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on March 21, 2020, 02:40:41 am
Updates have been accepted into the DFHack develop branch. Since we haven't yet reached the stage where DFHack is released as such, but nightly builds are made available, they're announced now (but if you don't build DFHack yourself you may have to wait another night for a build...).

Version 0.11 provides some new/changed functionality:
- Aquifer searches and display now distinguishes between Light and Heavy aquifers. The embark display can e.g. show "No Lt Hv" if the embark has some parts without aquifer, some with Light and some with Heavy.
- Min/Max tree search criteria have been introduced. I still don't understand why people want it, but now it's there...
- The largest addition is the ability to search for embark with particular neighbors (made possible through the identification of a previously misunderstood flag). This includes the ability to search for min/max necro neighbors. The neighbors are listed among the embark info, primarily because the Kobolds that the vanilla display suppresses are displayed.
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on March 21, 2020, 05:15:09 pm
Since we haven't yet reached the stage where DFHack is released as such, but nightly builds are made available, they're announced now (but if you don't build DFHack yourself you may have to wait another night for a build...).
"nightly" doesn't actually mean that - builds are usually finished within an hour, unless there are a lot of builds running.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on April 20, 2020, 06:40:19 pm
Ok, so here we go, after working on the indexing for the last couple of months I have a meaningful update:
I found an easy way to speed up (~10%, which translates into around 1:25 minutes for a 257x257 region) the search and also one to reduce the consumed memory significantly (~ 29%-36% of total used memory or ~ 77%-79% of the additional memory footprint of the plugin which translated to ~460 - 490 MB for a 257x257 region):
Have a look at
https://github.com/bseiller/dfhack/commit/9f53558267ef9f3769b310641d4c6fbc7e9576de
for the speep up - basically there were two maps being filled but never read (dead stores), removing them does the trick.
and here
https://github.com/bseiller/dfhack/commit/c07a0f1ff4cca85cd752ff26f358be49f8ec7cfe
for the changes to save memory - using a smaller struct with only those attributes that are relevant for incursions

I have incorporated those changes in my development - currently I use about 140MB RAM (some attributes are still missing) for the indices so I've still around 320MB to spend ;)
@PatrikLundell:
Let me know what you think.

PS: I also added some output to the console to make measuring the time a search takes more convenient:
https://github.com/bseiller/dfhack/commit/532cccde8a290c2f9e02d945c963c7fa3f65b063
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on April 21, 2020, 04:27:18 am
- Good find with the speedup. This comes from replicating the code from Prospector, but that tool actually uses the info to reduce the amount of minerals found when features are present, but that part isn't relevant to this code.

- Splitting the data into a part relevant to all and a part for the non incursion related stuff is a smart move.

- Adding a timer during the work is definitely useful. It can be commented out when the work is done (and uncommented when more work is needed: There's a reason for commenting out the "out" variables rather than removing them, beyond pure laziness).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on April 28, 2020, 05:14:36 pm
I was just going through the incursion processing code and stumbled upon this:
https://github.com/DFHack/dfhack/blob/6bdbf5b0ddaa045a8fc6ff91e91dc30cb3d21e3f/plugins/embark-assistant/survey.cpp#L2427
https://github.com/DFHack/dfhack/blob/6bdbf5b0ddaa045a8fc6ff91e91dc30cb3d21e3f/plugins/embark-assistant/survey.cpp#L2484
vs.
https://github.com/DFHack/dfhack/blob/6bdbf5b0ddaa045a8fc6ff91e91dc30cb3d21e3f/plugins/embark-assistant/matcher.cpp#L1083
https://github.com/DFHack/dfhack/blob/6bdbf5b0ddaa045a8fc6ff91e91dc30cb3d21e3f/plugins/embark-assistant/matcher.cpp#L1152
Shouldn't this be
embark_assist::survey::translate_ew_edge
in survey.cpp#L2427 and survey.cpp#L2484, too?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on April 29, 2020, 01:30:58 am
Yes, it should.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 04, 2020, 02:26:38 pm
Ok, good to know - that means it should be as well used here
https://github.com/DFHack/dfhack/blob/6bdbf5b0ddaa045a8fc6ff91e91dc30cb3d21e3f/plugins/embark-assistant/survey.cpp#L2427
and here
https://github.com/DFHack/dfhack/blob/6bdbf5b0ddaa045a8fc6ff91e91dc30cb3d21e3f/plugins/embark-assistant/survey.cpp#L2484
in embark_assist::survey::survey_embark


Never mind - having multiple branches of the sources in parallel is not easy on my memory :D

Do you want a pull request for that?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 04, 2020, 03:48:21 pm
I'll make one, thank you. I just haven't been in a hurry given that it's likely there won't be a new DFHack version for some time as the rate of change has slowed down.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 16, 2020, 02:57:26 pm
Ok, got it.

I think I might have found another bug, for real this time :)
Actually one could count it as two, but with the same pattern and the same fix.
Have a look at
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1922
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1996
If k is 15 (in the case of translate_ns_edge) or i is 15 (in the case of translate_ew_edge), which means the incursion would cross world-tile boundaries to the south/east a wrong/illegal value for biome_x/biome_y is being used (out-of-bound read access for i/k==16). Whatever memory is being read is being interpreted as int8_t, but might be something completely different.
There is no access violation or any other error thrown, but there is a chance that the incursion results for these corner cases are bogus - also depending on the regions of the two embark/mid_level_tiles
involved in the comparison.
Do you agree with my assessment?

If I'm right, the fix is two-fold:
1. store world_data->region_details[0]->edges.biome_x[0-15][0]/biome_y[0][0-15] in the region_tile_datum, similar to
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/defs.h#L116
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/defs.h#L117
retaining the the northern row of biome_x and the western column of biome_y.

2. add distinct cases when accessing biome_x/biome_y similar to
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1684
to
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1692
including adjust_coordinates as in
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1660

To allow for a 1/1.5 pass incursion processing I'll need the data anyway - so I can provide the necessary changes once I've made them and they work as intended.

Ah, and one actual question concerning the incursion processing at the edges of the world.
Of course there can't be any processing of edges from/to the outside of the world.
But what about the corners? Let's say we're at the southern edge of the world (y == world_data->world_height - 1 && k == 15).
Would it be possible to process the southern (-west/-east) corners to see if there is an incursion from/to the neighboring tile (i+/-1) within the same world-tile, ignoring the 2 non-existing corners/tiles further to the south?
Or would the needed data live in the non-existing southern world-tile neighbor (y+1)?
What about the other edges of the world (west/north)? Can those corner (north-west + south-west / north-west + north-east) be processed with the available data?
Long question short:
Is it possible to process corner incursion at the edge of the world with only two candidates and if so for which world-edges is it possible?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 16, 2020, 06:07:30 pm
Nope, not this time. For some reason Toady decided to make the structures 16*17 and 17*16, with actual data in the extra row/column. That's fine as it saves you from going to the next world tile to get the data, except that the corner, 16/16, is missing, so for that one you still need the that world tile.

I do agree that we really need the data for the other world tile(s) anyway to process the data properly, so that extra row/column doesn't help all that much.

For the western/northern edges the incursion info exists within the world, but there's special handling for the cases where the incursions are specified to come from the non existing side, which really affects corners only (for edges it's just a flip). Unfortunately, DF generates data indicating usage of data from the non existent tiles.
For the southern/eastern edges the extra row/colum provides the incursion info for everything but the corners (although you have to ignore it when going in the wrong direction for edges). While it should be possible to use the data for (0, 16) of the next world tile in the X direction (and correspondingly in the Y one, that's not how DF has implemented it. The corners along those edges all have the same pattern, i.e. the NW tile being the source (you can see that pattern if you use the showbiomes script on embarks along those edges).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 16, 2020, 06:18:36 pm
Nope, not this time. For some reason Toady decided to make the structures 16*17 and 17*16, with actual data in the extra row/column. That's fine as it saves you from going to the next world tile to get the data, except that the corner, 16/16, is missing, so for that one you still need the that world tile.
Hm, I can see that split_x and split_y are [16][17]/[17][16]
https://github.com/DFHack/df-structures/blob/cbeed8b52482ce749fc2ff13a9db9733931e7da0/df.world-data.xml#L418
https://github.com/DFHack/df-structures/blob/cbeed8b52482ce749fc2ff13a9db9733931e7da0/df.world-data.xml#L422
and neither split_x or split_y is used/referenced in the plugin code.
biome_x and biome_y seem both to be [16][16]
https://github.com/DFHack/df-structures/blob/cbeed8b52482ce749fc2ff13a9db9733931e7da0/df.world-data.xml#L437
https://github.com/DFHack/df-structures/blob/cbeed8b52482ce749fc2ff13a9db9733931e7da0/df.world-data.xml#L440
or as generated code
Code: [Select]
      int8_t biome_x[16][16]; /*!< 0=Reference is N, 1=Reference is current tile (adopted by S edge to the N) */
      int8_t biome_y[16][16]; /*!< 0=Reference is W, 1=Reference is current tile (Adopted by E edge to the W) */
Am I missing something?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 17, 2020, 05:36:07 am
Nope, the one who was missing something was me. I should have gone to bed rather than try to write an answer at that time.

The code works for the "own" case, but, as you point out, it doesn't for the "other" one, so yes, there is a need to cache the edge case data, and yes, the same kind of translation logic is the one you refer to is needed.

Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 25, 2020, 06:06:45 pm
Ok, so I finally found the time to adapt the code for incursion processing, which resulted in "uncovering" of the missing special cases (runtime errors) for the world-borders (northern world-bound [y=0, k=0], eastern world-bound [x=world_width -1, i=15], southern ... western ...) But I'm unsure how to handle those cases.
For the western/northern edges the incursion info exists within the world, but there's special handling for the cases where the incursions are specified to come from the non existing side, which really affects corners only (for edges it's just a flip).
By "flip" do you mean wrapping around to the other/opposite end of the world so e.g. southern tiles (y=world-height - 1, k=15) check for incursions against y=0, k=0?
Or just return "4" for no incursion here?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 26, 2020, 01:06:15 am
A "flip" is just reverse the incursion direction, i.e. returning 4.

Edit: I'm unsure how to interpret the comment about the "uncovered" cases. Does it mean your handling has trouble, or does it mean there's an issue in the released version? I don't get any errors when I try it along the world edges.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 26, 2020, 04:53:20 pm
A "flip" is just reverse the incursion direction, i.e. returning 4.
Ok, understood the handling of edges at the world borders.
I'll come back once it works and had another look at the incursion processing of corners.

Edit: I'm unsure how to interpret the comment about the "uncovered" cases. Does it mean your handling has trouble, or does it mean there's an issue in the released version? I don't get any errors when I try it along the world edges.
"manifested" would have been the better word.
Compare
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1916
till
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1925
with
Code: [Select]
if (own_edge) {
// the edge belongs to the currently processed tile thus its counterpart is the north tile (k - 1)
effective_edge = world_data->region_details[0]->edges.biome_x[i][k];
// region_type_of actually properly handles the case that we need information from the world tile north (y - 1) and returns df::world_region_type::Lake in case of y < 0, which prevents incursion processing
south_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k);
north_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k - 1);
}
else {
// the edge belongs to the tile south of the currently processed tile thus its counterpart is the south tile (k + 1)
// here the case that we need information from the next world tile south is being handled properly
if (k < 15) {
effective_edge = world_data->region_details[0]->edges.biome_x[i][k + 1];
}
else {
// outside of the world - so no incursion
if (y + 1 == world_data->world_height) {
return 4;
}
                // just the next world tile to the south
effective_edge = survey_results->at(x).at(y + 1).northern_row_biome_x[i];
}

north_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k);
south_region_type = embark_assist::survey::region_type_of(survey_results, x, y, i, k + 1);
}
The above line (reading cached data)
Code: [Select]
effective_edge = survey_results->at(x).at(y + 1).northern_row_biome_x[i];resulted in an illegal access error without handling the case
Code: [Select]
y + 1 == world_data->world_height were before it was just
Code: [Select]
effective_edge = world_data->region_details[0]->edges.biome_x[i][k + 1];which read invalid data but did not crash
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 27, 2020, 03:56:16 am
Ah, I see. Unfortunately, DFHack is FUBARed currently, so I can't do any kind of work with it.

Edit:
I've update the code with your discovery, although I've used the names north_row_biome_x and west_column_biome_y for consistency with the other names used.
Title: Re: DFHack plugin embark-assistant
Post by: Telear on June 03, 2020, 05:52:52 am
[ARGH! Ignore this! I forgot I'd asked this before, and that I didn't notice that Patrik has implemented something that means I can write my searcher as a plain old shell script. Onwards! And thanks so much for the change]

I'm not entirely sure if this is the right place to ask, or if I'd be better off starting a new thread, but I'm busily porting a fragile Mac only Keyboard Maestro script that generates lots of worlds and then runs embark-assistant over them in search of particularly rare embarks (in my case volcano + big waterfall + Iron + Coal, but in principle, anything that can be searched for), and it would be really useful if there were some information exposed to lua about search state and how many matching tiles have been found so that I could just fire off the search, and wait until either there was at least one matching tile or the search and completed. The Keyboard Maestro script was doing some horrendous screen scraping in order to detect when the search was over, and I really don't want to have to reimplement a similar mechanism in lua, because... ick.

I'd do it myself, but I have very little idea of what I'm doing in C++ land.

If that's not doable, is the search time linear with the area of the world being searched? In other words, could I fire off the search and then do something like

dfhack.timeout(world_area * a_constant, 'ticks', check_for_success)

and be confident that they search will have finished?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 03, 2020, 07:11:34 am
(Despite the Ignore this! statement)

It's possible to use a callback based Lua script to detect when world gen is done. If you make a callback at every frame (which is approximately equal to once per year once generation gets going, with some jumps throwing exact year matches off) you can check for various progress criteria (such as e.g. civ placement, good/evil placement, and, of course, reaching the end of the generation). Using that, you can have a script perform manipulations of the world as it's generated (I use it to tailor my PSV worlds to have all plants and creatures legal to regions being present, all glaciers being evil (that's where my glacier starting biome only gobbos start with their Blizzard Men slaves), etc. My slab_civ script uses the same harness logic to detect civs that ought to be dead and push them over the edge at the end of world gen.
I think only the "frames" callback works during world gen, as there is no time related concept that makes sense at that scale.
Title: Re: DFHack plugin embark-assistant
Post by: Telear on June 03, 2020, 07:29:18 am
Right... I saw your script that did that in your repo and it's cool, but I like the idea of making seeds that will reliably generate the interesting embark in vanilla DF, if only because it's a damn sight easier to distribute a simple text file than it is to send out a save file. I can sort of see the properties I'd need to be watching for worldgen, but I can't quite work out where I need to be looking to watch what embark-assistant is up to. Of course, now I'm wondering whether you could interleave embark-assistant with worldgen. Pause at year 0 and search for the physical geography features that are locked in at that point and throw a rejection if they're missing. Then, once you have matches, just keep looking at those as history is run to see if the 'dwarfish geography' of the potential site is right too. If there's sufficiently few interesting sites, searching that way might even be more efficient.

But that assumes the datastructures that embark-assistant needs are available during worldgen.

Once I've published a first cut at a unicorn finder script, I might see about repurposing the lua version of embark-assistant for a proof of concept – if it works, then I hope that once DFHack is back on its feet, it wouldn't be hard to expose the necessary bits of the plugin to Lua for shenanigans.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 03, 2020, 08:53:25 am
If embark-assistant can be run during world gen, you'd have to be very careful with the search criteria. For instance, if you look for an evil embark before good/evil has been placed, you won't find any. You would probably be able to run it at the start of history (you can try it yourself, by invoking it from the DFHack window), but it will still reflect evilness/savagery as it is at that time, not at the end of history, so even then you'd have to be careful.

However, when it comes to early aborts, I'd use a a Lua script for that and accept that a few of the candidates that are approved at that stage will fail at the final evaluation, in particular if the criteria don't require loading of the MLT info.
I've certainly used the strategy of aborting world gen early if Eye Ball Mk I assessment finds the world lacking.
Iterating over all the volcanoes, for instance, is more or less trivial using Lua. Just iterate over all the peaks (and there won't be that many of them), and look for the ones that have the volcano flag set.

By the way, DFHack is back: the change that threw things into disarray has been reverted until a solution to the problem has been found.
Title: Re: DFHack plugin embark-assistant
Post by: Telear on June 03, 2020, 12:03:50 pm
Right. I think you're getting caught up in the specifics of my example search target. I might want Volcano/Waterfall on a 3x3 with lots of neighbours, but someone else might want a big frozen river, magma in cavern one and joyous wilds in a 500 year old world. It seems (in theory at least) that I might be able to pause worldgen at the start of recorded history and run a limited embark-assistant that's only looking for the things that may have been placed at that point in time (Volcano/Waterfall/3x3, or Big Frozen River and Cavern 1 Magma) so worlds without those features can get rejected before we've sat around twiddling our thumbs waiting for 500 years to go by.

That said, in my original, fragile version of this, I just searched for the physical stuff with a 5 year history, then set the History, Name and Creature seeds to RANDOM, increased END_YEAR and added extra rows to my embark_assistant_profile.txt. It works, but it's fiddly and not great when I'm aiming at a DFHack script that anyone can run by setting up a search profile, then doing something like make-dream-embark PRESET at the DFHack prompt.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 03, 2020, 12:28:46 pm
I believe everything Embark-Assistant looks for exists at the start of history (it's trickier during the world gen part). Some things may change during history, though. I know Evilness and Savagery can change, and obviously neighbors can as well (if the Kobolds are wiped out they won't be neighbors anymore, and a civ settling or conquering one may come into range).  Obviously, the number of neighboring necro towers will change during history.
Evil effects may change as well, at least 100% tree death seems to be introduced to a whole region at a time (affecting only evil parts, but that's the whole region if it was evil originally), although that's not reported by Embark-Assistant, and effects introduced by spreading evil will obviously only affecting areas while they are covered by that evil.
I can't think of any other changes happening off the top of my head, though. Erosion cycles take place during world gen, not history, so the geography, geo biomes, and regions shouldn't change with respect to biomes. I assume creatures (and possibly plants) can go extinct during history, but, again, Embark-Assistant doesn't cover those.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 06, 2020, 05:25:22 pm
Hi there, I'm going through my incursion code from last night (yeah, it was late) cleaning up bugs and I think I found some bug predating my changes, looks like a copy-and-paste error, in fact two of them:
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1604
https://github.com/DFHack/dfhack/blob/f20446534bb7f39425e102bd70daec46e328004f/plugins/embark-assistant/survey.cpp#L1660
Shouldn't it be
Code: [Select]
adjust_coordinates(&effective_x, &effective_y, &effective_i, &effective_k);instead of
Code: [Select]
adjust_coordinates(&effective_x, &effective_y, &effective_i, &effective_i);?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 07, 2020, 01:30:07 am
Yes, using effective_i twice is definitely wrong, and the second instance should be effective_k, as suggested.
Title: Re: DFHack plugin embark-assistant
Post by: Schmaven on June 27, 2020, 11:58:24 am
I just used the embark assistant for the first time in this new version (my previous fort has been on a good run), and the new search is awesome!  Just wanted to say keep up the great work!
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 29, 2020, 03:30:20 pm
I might have stumbled over another bug....
Have a look here
https://github.com/DFHack/dfhack/blob/ee56d8157f62e5161f6248d9329d30e0c0ab314e/plugins/embark-assistant/survey.cpp#L1642
Declaring those 4 "*_region_type_level" as uint8_t results in an overflow (to 255/254) if a negative value is being assigned
which happens here
https://github.com/DFHack/dfhack/blob/ee56d8157f62e5161f6248d9329d30e0c0ab314e/plugins/embark-assistant/survey.cpp#L1748
and here
https://github.com/DFHack/dfhack/blob/ee56d8157f62e5161f6248d9329d30e0c0ab314e/plugins/embark-assistant/survey.cpp#L1754
This can lead to faulty _active flags which finally results in a wrong return value from the method.
At least nw_*, n_* and w_* should be int8_t, but for the sake of consistency it's easier have all 4 them be signed. Also the code could get changed later to assign a negative value to home_region_type_level as well, which might never happen, but still.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 30, 2020, 02:14:21 am
Yes, that's clearly faulty. Thanks.
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on June 30, 2020, 10:22:56 pm
I've got a question...

I've been using embark-assistant and I think it's really good.

The problem is that I have to gen countless worlds and run embark-assistant manually on each one.  so far I've spent the past week genning world after world, and none have had any acceptable embarks in them.

I know that there is a way to get DF to generate multiple worlds through the command line.

What I am wondering is if there is any way to generate multiple worlds and check them with embark-assistant automatically.  That way I could set it to generate and check fortresses while I sleep and (hopefully) wake up to a world with a suitable embark.

Also, it would be nice if you could expand the functionality for saving and loading search parameters so that sets of parameters could be saved and loaded by name.

Thank you.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 01, 2020, 04:03:02 am
The Embark Assistant currently supports a single profile that can be saved and loaded. You can manually switch between multiple saved profiles by shuffling the names of the file containing the profile (i.e. renaming the "old" one, generate a new one, rename the new one to something else, and then rename the old one back to the name used by the plugin-in.

The plugin also has an optional command line parameter that causes it to load the profile, perform a search, and generate a file containing the number of matches. From there is up to you (or someone else) to generate the rest, i.e. a harness that generates worlds, initiates a search, and evaluates the search result file contents. You might try to contact Telear (earlier in the thread) to see if a suitable harness has been developed.
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on July 01, 2020, 10:07:12 am
Interesting.

Had to dig into the code to find out where the file it generates is (turns out its in "data/init/embark_assistant_fileresult.txt").

I think this may be enough to get started.

Thank You!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 01, 2020, 10:11:11 am
The file location should be documented on the help pages.
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on July 01, 2020, 10:23:24 am
Ouch!  I tried using load-save to load the region from the command line but it looks like it only works for worlds that have already been embarked upon.  I did a quick search of the DFHack documentation but I couldn't find anything that would let me load a new world from the command line.  Am I missing something?

Also, the documentation for load-save has an improper example. 
The example says "./dfhack +load-game region1" when it should say "./dfhack +load-save region1".

Edit:

"./dfhack +embark-assistant fileresult" doesn't seem  to work either.

Does anyone know how to get from the linux command line to the "embark site selection phase" automatically?
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on July 01, 2020, 01:04:50 pm
Ouch!  I tried using load-save to load the region from the command line but it looks like it only works for worlds that have already been embarked upon.  I did a quick search of the DFHack documentation but I couldn't find anything that would let me load a new world from the command line.  Am I missing something?

Edit:

"./dfhack +embark-assistant fileresult" doesn't seem  to work either.

Does anyone know how to get from the linux command line to the "embark site selection phase" automatically?
It's possible, but due to the asynchronous nature of loading a world, it's complicated - probably more complicated than the load-save script. I'm not aware of an existing script that supports this at the moment.


Quote
Also, the documentation for load-save has an improper example. 
The example says "./dfhack +load-game region1" when it should say "./dfhack +load-save region1".

Yikes, that's a 4-year-old typo. Fixed (https://github.com/DFHack/scripts/compare/3987d0314694...5e300e6ed85c). The DFHack thread would be a better place to report things like that in the future, though, since it's not specific to embark-assistant.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 01, 2020, 01:35:18 pm
Thanks lethosor, those this is something I have no knowledge about.
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on July 01, 2020, 02:46:47 pm
Btw, if I specify more than one biome (e.g. setting both biome1 and biome2), does it check to make sure the embark has both biomes or does it check that there is at least one?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 01, 2020, 04:46:06 pm
It requires both. There's the more general region type covering a number of cases where you want one of a range (e.g. "any type of forest"). Each condition is on top of all the others except where stated specifically (there are some enumerated ones where alternatives specify various combinations, and there's special logic for evilness/savagery). It's mostly a case of me not being able to figure out how to display combinations of AND and OR conditions given the UI constraints.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on July 20, 2020, 04:06:42 pm
@PatrikLundell:
I think I'm done with the incursion processing.
Unless I'm still missing something (staring at survey::translate_corner (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L1621) and especially at #L1690 (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L1690) and at #L1693 (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L1693)), so just to be sure as it got lost in the details of the bug discussion:
...
Long question short:
Is it possible to process corner incursion at the edge of the world with only two candidates and if so for which world-edges is it possible?
I know it works for the northern and the western world edge.
But is there any way to process the corner incursions of the eastern
Code: [Select]
x == world_width - 1 && i == 15 && corner_location == 8
and southern world edge
Code: [Select]
y == world_height - 1 && y == 15 && corner_location == 8
with only the two eastern
Code: [Select]
i == 15 && k = [0-14] and k + 1
or southern
Code: [Select]
i = [0-14] and i + 1 && k == 15
corners that are available?
Or is there just no data (=> edges.biome_corner/region_tile_datum.north_corner_selection/region_tile_datum.west_corner_selection) to resolve those?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 21, 2020, 02:54:26 am
I'm trying to understand the question, but may still get it wrong....

x = world_width -1 and i = 15 with a corner location of 8 ought to result in an effective_x = world_width (and effective_i = 0) after having been processed by adjust_coordinates at line 1662, and thus be handled by the processing at line 1664, and similar for the southern edge (line 1677).
The reason for that overriding section is precisely that there is no data to read, and fallback values have to be used (and the fallbacks are what I've seen DF produce when I've looked at these edges).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on July 21, 2020, 06:25:17 pm
I think you got it perfectly right.
I'll lay out an example, so there is less room for misinterpretation on my side.
So, lets look at the south-east corner case on the southern edge of the world.
I'm debugging this in a pocket world, 17x17, let
Code: [Select]
x == 14
y == 16
start_y + finder->y_dim - 1 == 15
the last one translates to k == 15
so my breakpoint condition for this line (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/matcher.cpp#L1032) is as follows
Code: [Select]
x < 16 && y == 16 && start_y + finder->y_dim - 1 == 15
I just stepped from
matcher::embark_match, the "SE corner south row" case (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/matcher.cpp#L1033)
to
survey::translate_corner (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L1682)
which only happens for the southern edge of the world (effective_y == world_data->world_height), when looking at the south-east corner (corner_location == 8 ).
translate_corner returns 3.
Taking this value to
survey::process_embark_incursion_mid_level_tile (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L585)
which means we get the data for the south-east corner incursion from the western neighbour (i - 1) of the currently processed tile, correct?

Is that the logic to produce the fallback values you mentioned
The reason for that overriding section is precisely that there is no data to read, and fallback values have to be used (and the fallbacks are what I've seen DF produce when I've looked at these edges).
?
Or am I not seeing something here?
(It's getting late and I might be a little confused :)))
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 22, 2020, 02:12:06 am
That's clearly wrong, as you point out.

I'm having trouble remembering what the behavior was, but assuming the overall logic is correct, the "3" should be "5", i.e. the eastern tile, not the definitely incorrect western one. If that eastern tile doesn't exist effective_x would be world_width, and so caught in the first section, so that tile should always exist.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on July 22, 2020, 01:39:11 pm
That's clearly wrong, as you point out.
You give me too much credit for this one.
I wasn't even assuming that it might be wrong - I just wanted to understand the logic/process.

If line 1682 always returns 5 (eastern neighbour is incursion source) for every south-east corner incursion at the southern edge of the world without regard for the region type, than that also means that every tile (but the last) has an incursion from its eastern neighbor, doesn't it?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 23, 2020, 03:47:35 am
Well, you did flag "western" as suspicious, and rightly so, as the only legal alternatives for those corners are self, E, S, and SE.

Not quite, as line 1679 returns "self", so the alternatives are "self" and E for those tiles.

However, it seems that the code should have compared the region types and swapped the results around where appropriate, so a straight "return X" seems to be hasty.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on July 23, 2020, 05:22:36 pm
Haha, yes, suspicious fits quite well.

Ok, so instead of returning 3/5 directly in L1682 the flow would need to continue along the function, while skipping L1686 till L1694, as neither biome_corner nor *_corner_selection are available/contain valid data for this case.
This makes setting a proper/correct value for effective_corner in the else-branch necessary, one that will lead to a correct return value of the function - I'll look into it.
embark_assist::survey::region_type_of actually handles none existing tiles pretty well (returning Lake), so no need to change anything there.
That also means that the non-existing corners/tiles will receive a low *_region_type_level which should sort them out automatically.
I'll have to run some tests...

Thanks for your ongoing support, I really appreciate you taking the time to answer my never ending questions!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 24, 2020, 03:12:49 am
I'm impressed that you're putting all that effort into updating the code, and you've proven that the code needed a code review as well. Thanks for that.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on July 25, 2020, 04:06:45 pm
Well thank you :)
Once we had our initial exchange I just couldn't let go of it and up until now there wasn't any total road block that prevented me from carrying on.
Also embark-assistant is quite different from my day job which intrigues me and yet it is similar enough that my skills, experience and intuition are helpful.
It's like a very time consuming riddle - soon it will be a year. :o

Having said that, I was thinking: Isn't what we have concluded in our previous posts true for the south-east corner at the eastern edge of the world as well - always returning 4 in survey::translate_corner (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L1673) if 7 could by a valid value too seems strange ...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 26, 2020, 02:41:29 am
The logic for the south edge corner is reflected for the eastern edge, but rotated 90 degrees in the form of "5". The valid value of 7 results in an effective_x of world_width -1, and thus would be handled by the regular code further down.

Remember that each corner has 4 different possible outcomes, and the special handing applies only to the two of them that would refer to tiles outside of the map (and the extra special case of the very SE corner of the world is handled just above, always returning "4").
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on July 26, 2020, 05:34:47 pm
I think I get what you are saying.
But what I mean is this: Being at the eastern edge of the world, (effective_x == world_data->world_width && i == 15) and looking for incursions on the south-east corner here (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L1673), there are two valid return values at this point, 4 and 7, the current tile (4) and the tile south of the current tile (7) (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L601).
But translate_corner always returns 4 for this case - shouldn't the region_type factor into the return value here as well - in fact for all special "edge" cases except the first (https://github.com/DFHack/dfhack/blob/044add214710434a6d0fddb30b48209d3ed0f017/plugins/embark-assistant/survey.cpp#L1666)
However, it seems that the code should have compared the region types and swapped the results around where appropriate, so a straight "return X" seems to be hasty.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on July 27, 2020, 04:59:56 am
Ah, that's what you meant!
Yes, it should perform that evaluation, but I thought we'd already drawn this conclusion (for the southern edge, which should apply to this one as well), which is why I took your comment literally, rather than involving the larger context.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on August 04, 2020, 06:19:49 pm
Ok, I'm doing some embark science via sampling edge cases (neighbor with aquifer incurs into neighbor without aquifer ...)
And I'm wondering: How far does an incursion reach into the receiving embark tile?
I've seen something about 12,13 (small) tiles?
Or is this coincidence with my samples and there is no rule for the "depth" of an incursion?
Asked differently: Does an incursion via a corner into 3 other embark tiles concentrate in the complementary corners of the receiving embark tiles?
Or is incursion more defined along the line of: receiving embark tile has now sand not only along its edge or the incurred corner but spread everywhere in its 48 x 48 area.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 05, 2020, 02:28:17 am
I'm not sure about the exact logic for incursions, but I believe the edge information about where the division of the edges into sections result in four points in the tile acting as starting points for the divisions, and random generation then generates boundaries from those points out to the edges. If the incursion goes into the neighboring tile instead, the point doesn't have any effect for that incursion on the current tile, but instead affects the neighboring tile (where the division point in the other dimension doesn't have to have the same value).


*  10 40  *
11        13
38        41
*  12 36  *

would result in the points (10, 11), (40, 13), (12, 38), and (36, 41). The divisions along the edges are shared with the neighboring tile on the other side, so the top eastern corner of the tile to the west of the one above would  be (x, 11), where x is given by the value on its norther border.

It should be noted that it's how I think it works, but I haven't confirmed it. I've confirmed that the coordinates along the borders do not match where the borders are divided themselves (i.e. in the above example, the division between the NW incursion and the N one [or the native one, if the N incursion goes outwards] doesn't appear at X = 10, but typically further away).

I'm not sure the confused rambling above makes sense, though...
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on August 05, 2020, 03:49:25 pm
Hehe, it might be confused rambling for you, but I can relate.


*  10 40  *
11        13
38        41
*  12 36  *

Let me paraphrase one key takeaway: The offset/division of the dimension/edge (horizonal - x/vertical - y) that is shared with the neighboring tile is used in both cases either if the incursion is incoming or if the incursion is outgoing to the neighboring tile.

Is the above by any chance another way of representing this schematic (https://github.com/DFHack/df-structures/blob/b439f22876634725f246703e3ac8a7a0b1a01d63/df.world-data.xml#L375)?
That would mean I could try and use the data from split_x and split_y to verify my assumptions?
And if I understand correctly the split/division data should be the same for the edge that two neighbors share?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 05, 2020, 04:07:14 pm
Yes, that's the info my image was based on.
The one coordinate the neighbors share has to be the same, yes, with the other coordinate shared with the appropriate neighbor in the other dimension. As you can see, the split_* matrices only has a single value for each tile, reflecting this sharing.

If my memory is correct, Toady mentioned the name of the algorithm used to create the incursion boundaries, but I don't remember the name and don't think I've looked it up to understand it either. I believe this mentioning was done during the last year or so, but don't know which forum it was in, although I think it was written.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on August 05, 2020, 04:51:40 pm
I wrote the split_* of an world tile into a file (see below) and I have to confess: I can't see the sharing in those values, not really -
here it says (https://github.com/DFHack/df-structures/blob/b439f22876634725f246703e3ac8a7a0b1a01d63/df.world-data.xml#L419)
for split_x:
Quote
for horizontal edges, x=min y=max
So there are two values for every split (for example 15,36 which means in the case of a split_x that the split starts at x = 15 and ends at x = 36, yes?) and I'd expect, that (15,36) would be repeated in the next line again - wait - ah.
I think I get it: The splits "lie" between the tiles, starting left/above the first tile and ending after the last tile right/bellow, so two tiles share the split between them.
Looking at the data between to world tiles I see the same splits at the shared edge, so there is some redundancy - which is good I might not have understood it otherwise :D

So taking a look at split_x data below at (0,1) => 16,33
This split is shared between the tile at 0,0 and 0,1, yes?
And the split at (0,0) => 15,36 is shared between the embark tile 0,15 in the world tile above the current tile and the local embark tile at 0,0, right?

split_x:
Spoiler (click to show/hide)
split_y:
Spoiler (click to show/hide)
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 06, 2020, 03:25:57 am
Yes. The 17:th value should be a copy of the first one for the next world tile, and so should be redundant (but remove the need to get the data from the next world tile).

As far as I understand it (which might not be correct, which is an important caveat), the x, y values don't say much about where the border is crossed, but rather team up with the other values to form 4 points within each tile. Each of those points then get four paths from them, one for the nearest horizontal edge, one to the nearest vertical edge, and one to each of the two neighboring anchor points, with the paths generated through an algorithm. I think the algorithm can actually result in lines that go "inwards", so the anchor point is further away from the corner on one axis than the point at which the edge is crossed, and I believe I've seen incursions split into several small sections because the line effectively hit the edge.


                   1              2               3              4
   012345678901234567890123456789012345678901234567
 0 000000000000011111111111111111111111111122222222
 1 000000000000001111111111111111111111111112222222
 2 000000000000111111111111111111111111122222222222
 3 00000000000*111111111111111111111112222222222222
 4 0000000004444444444111111111111444*2222222222222
 5 ...

0 = Incursion from NW, 1 = Incursion from N, 2 = Incursion from NE, 4 = Self, * = Anchor point.

The first * would be formed from split_x [self][self].x and split_y [self][self].x and the second one from split_x [self][self].y and split_y [self + 1][self].x. In the "image" above I've come up with two (short) paths to the northern edge from the two northern anchor points, and some hint of the other paths.
Also note that it would be possible to make these paths regardless of whether they're used on not (the latter would be the case for an incursion going outwards).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on August 08, 2020, 05:17:25 pm
The first * would be formed from split_x [self][self].x and split_y [self][self].x and the second one from split_x [self][self].y and split_y [self + 1][self].x.
So if I got that correctly this would mean, that
the third * would be
split_x [self.x][self.y + 1].x / split_y [self.x][self.y].y
and the fourth * would be:
split_x [self.x][self.y + 1].y / split_y [self.x + 1][self.y].y

Correct?

This might help me to check for plausibility on how south-east corner incursions at the edge of the world behave - if I find a proper candidate that does not have an incoming incursion on the edge connected to the relevant corner. Otherwise it's hard to tell which incursion really brought the aquifer/clay/sand.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on August 09, 2020, 01:06:58 am
Yes, that's how I believe it works.
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on September 16, 2020, 06:14:16 pm
Hey, I've got a quick question here:

I seem to remember that when I first installed DFHack for this version (and embark-assistant along with it), that the number after the text "Matching World Tiles:" in embark-assistant was yellow while embark-assistant was still searching (but hadn't found anything) and then turned either green (if it had found something) or red (if it had searched the whole map and found nothing).

Then when I upgraded to a newer version of DFHack (and embark-assistant) it seems to have been changed so that the number stays yellow no matter what.

I'd be interested in knowing the reason(s) behind this change.

Thanks in advance!

Edit:

Found something else interesting while doing a quick test to ensure that it really did leave the number yellow after having found matching sites:

It looks like embark-assistant searches most of the map using 4x4 squares of world tiles, then when it gets to 4 world tiles from the bottom, it switches to using 3x3 squares, and then for the very bottom row switches to 1x1 squares.

Interesting...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 17, 2020, 01:30:47 am
The expansion to take incursions into consideration made the distinction between a tentative match and a full match somewhat iffy (full processing of a world tile relies on the surrounding world tiles being processed, which means either doing two passes automatically to catch everything, or let the user do the second pass, which is the current implementation).

The processing of world tiles processes one "feature shell" (16*16 world tile blocks) at a time to minimize DF's feature shell loading, one feature shell row after another, with alternating rows going towards the right and to the left, and within the feature shell the processing is one column at a time, alternating between down and up. At the right edge the feature shell is 1 * 16 world tiles, at the bottom it's 16 * 1, and at the lower right corner it's 1 * 1. The reason for the convoluted movement process is to minimize the generation of region_details info by moving a single world tile at a time (the process to move to a different tile is done by simulated key strokes sent to DF, as the author is not aware of any other way to get DF to shift its focus to a specific tile), so each world tile should be visited exactly once.
The progress is then displayed as callbacks to the display functionality once every so often to provide the user with some feedback during the lengthy process.
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on September 17, 2020, 06:48:55 am
The expansion to take incursions into consideration made the distinction between a tentative match and a full match somewhat iffy (full processing of a world tile relies on the surrounding world tiles being processed, which means either doing two passes automatically to catch everything, or let the user do the second pass, which is the current implementation).

What is meant by "or let the user do the second pass"?  Does this mean I should run embark-assistant's find function twice?

The progress is then displayed as callbacks to the display functionality once every so often to provide the user with some feedback during the lengthy process.

I'm still wondering why (even after the process is done) the number still stays yellow instead of turning red or green like it did in the previous version.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on September 17, 2020, 10:43:46 am
The expansion to take incursions into consideration made the distinction between a tentative match and a full match somewhat iffy (full processing of a world tile relies on the surrounding world tiles being processed, which means either doing two passes automatically to catch everything, or let the user do the second pass, which is the current implementation).

What is meant by "or let the user do the second pass"?  Does this mean I should run embark-assistant's find function twice?
If you are looking for absolutely all matches than yes, that is what you need to do.
After the first pass it is possible that some matches have not been found. These possible matches are at the outer edge of world tiles and depend on the incursions from other world tiles, which are only available in subsequent passes after the first one.

I'm currently working on a variant of the existing search routine that finds all matches in the first pass, but it's not done yet -

@PatrikLundell: but i'm pretty close now, the iterative search (one world tile at a time as soon as all necessary data has been collected) during the survey phase works, the additional work that needs to be done to get all incursion data during the first pass has been moved to another thread where possible, which results in a 2 minute speed up => ~10 minutes for a 257x257 world.
I postponed any research regarding south-east corner incursions at the world edge till after all features are there - for growing world sizes this case becomes less and less important compared to the total number of embark tiles...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 17, 2020, 11:36:14 am
There is a bunch of help pages in the plugin. Those should describe most of the functionality. In order to get the fully correct search result you should run your first search twice. After that the incursion processing dependent info has been collected and cached, so any further searches yield the fully correct result (the second search does not have to be a copy of the first one, but can be something else).

The reason the results after the first pass are yellow is that they're not definite.

@RedDwarfStepper: Looking forward to see what you've come up with. I agree looking into a special edge case is better done after the bulk has been done (as long as that edge case doesn't have the potential to overturn the whole thing, which isn't the case here [as it's also a literal edge case]).
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on September 17, 2020, 12:16:41 pm
Code: [Select]
Loading bindings from data/init/interface.txt
New window size: 800x300
Font size: 10x12
Resizing grid to 80x25
Resizing font to 10x12

Resetting textures
DFHack is ready. Have a nice day!
DFHack version 0.47.04-r2 (release) on x86
Type in '?' or 'help' for general help, 'ls' to see all commands.
matcher::find: Preliminarily matching World Tiles: 246
matcher::find: Preliminarily matching World Tiles: 0

Note: last line should be in red.

This is the output from my latest run of DF, DFHack, and embark-assistant.  I started by genning a world.  I then loaded that world and ran embark-assistant's find function on it.  As you can see from above, it initially reported 256 preliminary matching world tiles.  Unfortunately, it failed to find any matches.  Then I ran the search a second time.  This time it immediately returned with a red message saying that there were 0 preliminary matching world tiles.  From what I can tell, it does not appear that any second search even ever took place.  Embark-assistant seems to have returned from the second search without ever conducting it.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on September 17, 2020, 12:57:16 pm
A speculation, without looking at the code, is that the original logic that aborts search on 0 possible matches might remain, while it should perform the second search (but not further ones) to finish the job. There's code in there to check tiles known not to have any matches if the second run hasn't been done yet, but the original assessment might cut that short in the zero match case.

If that guess is correct, it's debatable whether the text should be yellow or red, because the tools would then "stupidly" go away for a long time to search even if it's already known there are no matches (when it works as it should).

Edit: Yes, the code skips out of both the first and the second survey when the preliminary matching rules out the presence of any candidates (although there aren't that many realistic searches that would fail before the first one).
Thinking it over again, I believe it should skip out as quickly as possible (i.e. current behavior), as it would allow the user to refine the search for the "real" search process, rather than wasting time building up search info.
As far as I can see from the code, the second line in A_Curious_Cat's case should indeed be returned in red, as it's printed with "out.printerr", which does print in red (as opposed to the "normal" case which uses "out.print" which doesn't change the color). Trying to replicate the problem fails for me, as all the cases of 0 matching world tiles come out in red, so it might be an issue with the DFHack terminal (I've had various issues with the Windows one in the past, in particular with getting color to behave correctly).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 10, 2020, 06:42:26 pm
Ok, I think I'm on the final stretch
And a browser crash ate the previous, half-finished version of this post :)

Anyway on my second screen is an ugly, multicolored spreadsheet, that lists all ~40ish criteria that need to be implemented in this version of the plugin (I'm still working with 0.44.12-r2, planning on adding all new criteria once I've got all the old ones working).
Some 20 have a cyan background which means they are implemented and have passed a first series of tests.
4 are a (not really) beautiful magenta, telling me they need to be tested more thoroughly*.
The rest are yellow, they still need to be implemented.
To verify the results of the new search I use the results of the existing code and diff them with the new ones.

*Of course, the first time I wrote this I just had done some more tests that brought up some interesting questions:
- Is it by design or by organic/historic growth of the code, that incursions don't count to the fulfillment of the "all" option of savagery, evilness and aquifer ("all" became "light" or "heavy" here)? And in extension also the "absent", "not all" and "partial".
In matcher::embark_match there is a block of tests concerning savagery, evilness (line 617 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L617), line 630 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L630) and line 638 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L638)) and aquifer (line 663 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L663)) before the incursion handling is done -
if the embark tile doesn't contain the "resource" natively there is an early exit with a negative result. In matcher::process_embark_incursion there are the equivalent checks (line 95 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L95), line 111 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L111) and line 145 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L145)) but those can't be reached because of the early exits in the calling method (=> process_embark_incursion_mid_level_tile => process_embark_incursion).
Please tell me this is not by design, I'd really hate to need to change the index code to adapt to this. :D
- The second question is more of a finding, which I wanted to run by you to make sure I'm not missing something:
I have a small world I use for tests (find the save here (https://dffd.bay12games.com/file.php?id=15295)), and searching just for sand:present results in less world tile matches the second time around, where one would expect more results. Looking into it I found two reasons/flavors of the same problem:
1. All *_count fields of region_tile_datum get initially set in survey::high_level_world_survey (line 807 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/survey.cpp#L807)  + line 864 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/survey.cpp#L864)) depending on the values of geo_summary.
This represents potential matches, e.g. a world tile might contain sand (...) based on the layers it contains.
Then the *_count fields get reset in survey::survey_mid_level_tile (line 1284  (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/survey.cpp#L1284) + line 1300 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/survey.cpp#L1300)) based on the actual data of embark tiles.
For all world tiles that can potentially contain sand (/any other feature that can be incurred) but actually have no embark tiles that natively contain sand this leads to less matches in all subsequent searches after the first one as they are no longer considered a preliminary result in matcher::world_tile_match (line 1671 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L1671))
For this case there is an "easy" fix, one could add something along the lines of
if (result.sand_found && region_tile_datum.sand_count == 0) {
   region_tile_datum.sand_count++;
}
in line 1263 (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L1263).
Which read like this: If there are any sand (/...) incursions but no native occurrences then the world tile still contains sand (/...).
2. If a world tile doesn't even potentially contain sand (/...) natively than the above fix does not work, it will never be considered a preliminary match and thus never be included in the matching.
In those cases there would have to happen a "lookaround", as the world tile could get incursions from neighbornig world tiles. This of course can only happen in subsequent runs after the first, otherwise the data is not available.

I haven't looked into this "lookaround" any further, not having a lot of time and being unsure how big a change it would be. But not having the original results to compare the matches of the new search against is unsatisfactory :)
I might have a go on all non-incurred features first and come back later to this...

But most importantly: Can you reproduce my findings with the provided save? And if so: Whats your take on them?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 11, 2020, 05:23:15 am
-Incursions vs savagery, evilness, and aquifers: Those are conditions that ought to take incursions into full consideration.
  - As far as I can see, lines 630 and 638 are reached only on absence together with the demand for All which looks correct to me?
  - Similarly, if a Light aquifer is demanded (rather than e.g. At_Most_Light) but isn't present, I believe the criterion not to be met?
  - The checks on incursions ought to check what the incursions contain. If the check failed because the native tile didn't meet the All criterion you shouldn't get here, but if it did, you should fail if the incursion doesn't meet the criterion, even if the native tile did.
  Thus, it looks correct to me, but you've found bugs it took me some time to recognize in the past...
  So, as per the request, I tell you that the design ought to take incursions into full consideration for savagery, evilness, and aquifers, and I think it does ;)

- Sand (which is, of course, only a representative of similar things):
  - The initial sand tile count can be too high because erosion can't be taken into account at that stage, but this value shouldn't carry into the results of the first match, as the first match should evaluate every tile unless it finds that it should be impossible to get any match at all (i.e. immediately reporting 0 matches), and the matches reported should be the verified correct ones (i.e. not counting the ones where incursion processing has to be done at the second match).
  - I believe you're correct in that logic to propagate sand provided by incursions from neighboring world tiles is missing, causing subsequent matches to fail to find some of them.
(I wonder if this is the problem A_Curious_Cat had but failed to reproduce?).
- I think this issue means the second search has to be complete as well, i.e. the logic that causes all world tiles to be surveyed on the first pass ought to be extended to also include the second pass. If the first pass cached the native results (i.e. your work), the second pass should be able to be performed using cached data only.
I'm not sure where the code making sure incursion effects are propagated to the world tile summary should go. It would require a bit of work to determine that.
- I haven't looked at your save, but I believe the above (based on your findings, of course) shows there is a logical hole that ought to be capable of reporting sites on the first pass that are then failed to be found on the second. At the same time, the second pass should be able to find sites that were not included in the first one because they hadn't been fully evaluated (which is intended). Logically, there should be cases where the first number ends up higher than the second one because of the bug.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 11, 2020, 06:14:12 pm
tl;dr:
I started to write a reply and had to take a break, which allowed me to change my perspective.
I think we might have different definitions of "all".
At least the code and you saying
...
  - As far as I can see, lines 630 and 638 are reached only on absence together with the demand for All which looks correct to me? 
  - The checks on incursions ought to check what the incursions contain. If the check failed because the native tile didn't meet the All criterion you shouldn't get here, but if it did, you should fail if the incursion doesn't meet the criterion, even if the native tile did.
  Thus, it looks correct to me, but you've found bugs it took me some time to recognize in the past...
  So, as per the request, I tell you that the design ought to take incursions into full consideration for savagery, evilness, and aquifers, and I think it does ;)
make me think that.
I also think both definitions are valid, it might come down to taste and pragmatism, memory requirements for data storage might also be a small factor...

Your definition requires all native embark tile data and all incoming incursions to match the specified characteristic (e.g. high savagery), being exclusive, no other characteristics (e.g. low and medium savagery) in any form allowed.
This produces fewer total matches with embark areas that have either no incoming incursions or are situated deeper inside of pure fields of the required characteristic (e.g. untamed jungle biome all around the embark area).

My definition of "all" is less strict: As long as every embark tile in the embark area has at least one correct match (either native or by incursion) that is sufficient.
This will produce more total matches, some of which are less deep inside of absolute characteristic fields e.g. at the edge of a zone where other characteristics with outgoing incursions (= incoming into the embark area) can be found.
To retain the functionality of your definition I could add a "all exclusive" parameter or even distinctions "all_complete", "all_at_least_native" - the latter would make additional indices necessary as the native data would need to be stored separately from the incursion data - which I'm not a big fan of.
And by using "absent" on the other characteristics one can force the matching to behave just as strict as with your definition, while being able to distinguish more detailed e.g. evil:all + good:absent allows for neutral spots by the less strict definition.
There is also a rather small argument to be made about "all" and "absent" being more symmetrical if “all” is less strict defined – see below in the last paragraph of the original reply.

Could you live with my definition of "all" - at least for the time being?

Original reply:
Okay, lets take a broader look - first the definition of "all" also in comparison to the other requirements:
> All as a parameter means every embark tile has to have this value.
My interpretation of this is as follows: All embark tiles that are part of the currently examined embark area (e.g. 4 x 4 = 16 tiles) must contain the specified characteristic, either natively, via incursion or both to satisfy the criteria.
> Present means at least one embark tile has to have this value.
At least one embark tile must contain the characteristic, either natively, via incursion or both to satisfy the criteria (=> savagery_found[LEVEL]=true; embark_match (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L619) / process_embark_incursion (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L82) )
> Absent means the feature mustn't exist in any of the embark tiles.
No embark tile can have the criteria, neither native nor via incursion.

Looking in the code the way "present" and "absent" work are pretty clear. For the first one single hit (natively or incursion) is enough to satisfy the whole criteria resulting in a match, for the second one single hit (natively or incursion) is enough to prevent a match.
But looking at how "all" works, there is a difference: The hit must be native at least and if there are any incursions each and every one of those must have the correct characteristic as well.
Lets have a small example:
We have set the filter for High Savagery:all, the dimensions to x:2 + y:1 => 2 embark tiles.
Currently an embark area is being processed.
The first embark tile has native High Savagery and passes this condition (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L624).
All incursions going into the first embark tile also have High Savagery, and thus pass this condition (https://github.com/DFHack/dfhack/blob/0958fdbf4b38791468f69e590793bf9f512a6626/plugins/embark-assistant/matcher.cpp#L87).
The second embark tile also has native High Savagery and passes the condition in embark_match.
All incursions but one have High Savagery, one has Medium Savagery. This results in the embark area not being a match.

That makes "all" more like an "exclusive all", as it enforces that there can't be anything else but the specified characteristic.
Which is unusual as no other criteria defines requirements for other characteristics at least in the "old" version I'm currently working on, no sure about the two different variants of aquifers and forests in the current version...
This is also less intuitive as there is an explicit way to force this exclusivity: Using "absent" on all characteristics that should not be present.

The new code currently handles "all" as I understood it originally: All embark tiles must provide at least one hit for the requested criteria, either native or via incursion, but apart from that it is okay for them to have other characteristics either natively or via incursion as well.
This is symmetrical with "absent": a single hit for an embark tile is enough to (dis)qualify that embark tile, one missed embark tile disqualifies the whole embark area
Also this leads to more matches - which can be nice or not, really depends, but that can be controlled via "absent".
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on November 11, 2020, 07:08:47 pm
(I wonder if this is the problem A_Curious_Cat had but failed to reproduce?).

I think it did have something to do with sand.  I, also, just realized that I may have made a mistake when I tried to reproduce the problem.  Back when I first applied for an account on DFFD, I made sure that I could reproduce the problem.

The correct sequence to reproduce the problem (with the save that I was planning on putting on DFFD) was (IIRC)

1.  Load the world by choosing "Start Playing" and "Dwarf Fortress" mode and use embark-assistant to search using the search parameters that I planned to provide in a screenshot (which did not require that sand be present) and then search again (according to what I've heard about needing to always search twice with the same parameters).  This should have resulted in a number of potential embarks being found.

2.  Abort the game and return to the main menu.

3. repeat the actions in step 1 with the exception of changing the search parameters to require that sand be present.  This should have resulted in no embarks being found.

4. Without repeating actions in step 2, change the search parameters back to the way they were in step 1 and perform search again (remembering to search twice with the same parameters).  This should have resulted in no embarks being found (conflicting with the results from step 1 even though both searches used the same parameters).

I think my mistake was that I forgot to do step 2.

Anyways, that world has since been deleted after the fort I made on it imploded.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 12, 2020, 05:00:28 am
I'm not a fan of your definition of All as "present in all tiles", rather than being the reverse of Absent.

It's true that you can achieve the original (i.e. no intrusion processing) functionality of All with Present for the desired criterion and Absent for all of the others, but it's not a user friendly and intuitive way of setting the criteria, which is why All was introduced.

With your definition of "All", players that selected Good:All and Savagery:Low:All could end up getting an embark with all tiles being Evil and Savage natively , with your criteria being fulfilled by some incursions that are Good and some of which have Low Savagery for every tile, as long as the embark isn't larger than 2 in at least one dimension (this extreme outcome would be very uncommon, of course, but would also be the cause of bug reports).

If you think there would be a demand for your versions of "All" I would satisfy that by two new criteria called something like "Present_As_All_Tiles" and "Present_In_All_Tiles", where the former would demand that the tiles themselves meet the criterion, but allow incursions to differ, and the latter would be satisfied with all tiles meeting the criterion either in the tile itself or through an incursion. I'm not convinced there's a demand for those criteria, though.
  I can't come up with a scenario where I'd ever somehow would want a feature present in all tiles but being satisfied with it being provided by a tiny incursion somewhere in it: If a small incursion would be sufficient, it would probably be enough to have it anywhere in the embark, rather than demand it in every tile.
  I can make a case for demanding every tile to meet the criterion natively while allowing for incursions to differ as it might result in a smaller set of matches when you want the dominant part of your embark to match the criterion, but incursions vary a lot in size, so that's more an illusion of control that actual control.

In my view Absent and All are symmetric: Any presence invalidates Absent, and any absence invalidates All.

On the issue of dealing with incursion propagation to the world tile summary, I've thought about it and currently believe it can be handled in the current version by:
- At the end of the survey of each world tile, post process the tiles along the edges in the previously processed neighboring tiles to process incursions into them for the purpose of propagating the info to the world tile (but not affect the search results). The processing would need to defer processing of the lower right corner until all four of the touching world tiles have been processed, and it would need to process world edge tiles as if the fictive world tile on the other side has been processed already.

With your caching, I'd probably aim for a three step process:
- Process all MLTs in all world tiles.
- Process all incursions into all MLTs. However, it might be that it may be better to keep incursion processing for the interior MLTs in the first stage, as is done currently.
- Perform matching against all the fully processed MLTs. This step would be the only one needed for matching attempts after the first one.

Edit: My approach to deal with the incorrect top level data won't work: You need access to all the surrounding MLTs to process incursions, and attempts to process incursions as they become available would require the storage of both the native MLT results and the partial summary. Back to the drawing board...
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 12, 2020, 05:11:46 pm
@A_Curious_Cat:
I just reread your previous posts and your last one and yes, that seems to be the problem I've found as well.
But leaving/aborting to the main menu is not necessary to provoke this behavior, at least that's my observation.
It is sufficient to have a world save that contains a "specific" configuration (which is actually quite common, or so I think) of characteristics (like my save here (https://dffd.bay12games.com/file.php?id=15295)) and to search twice, with the same or at least similar parameters in a row. Those characteristics include aquifer, clay, sand, flux and coal others as well. Three of those are eligible for incursion processing: aquifer, clay and sand, which is relevant.
What happens is as follows:
- after starting embark-assistant (via console or automatically via init somehow) an initial high level world survey processes all world tiles exactly once. It identifies potentially existing characteristics using counters to keep track of the number of occurrences a characteristic mighthave within a world tile.* These counters are being used to decide if a world tile is a preliminary match and thus will be processed during matching
- after starting the search the number of preliminary matches is being evaluated, based on the counters containing potential numbers  => more preliminary matches than later on
- during the very first search run a more detailed survey takes place that evaluates all 256 embark tiles in every world tile. The counters are being reset to contain the actual number of occurrences of every characteristic, which might be lower than the previous value, even 0.
- where possible cross world tile incursions are being taken into account which in some cases result in incoming characteristics# (aquifer, clay or sand!) that actually don't natively exist inside the world tile but potentially could have as discovered during the initial high level world survey (<= this is the kicker! These two circumstances * + # aligning in some world tiles produces matches that won't reappear with the second search)
- the matches of the first search run are being displayed
- the second search is started, with unchanged or slightly modified search criteria, still containing at least one of the above mentioned characteristics.
- during evaluation of the preliminary matches all world tiles that have a relevant counter of zero are no longer considered a preliminary match and won't be processed during regular matching (no cross world tile incursions!) and thus won't produce a match even if they should => less matches than before.

And to make it even more interesting: That some previous matches are missing might be disguised by the fact that the second and all subsequent searches often result in more total matches as all world tiles are fully surveyed which makes the complete processing of cross world tiles incursions possible.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 12, 2020, 05:42:48 pm
@PatrikLundell: I stand corrected.
I'm not a fan of your definition of All as "present in all tiles", rather than being the reverse of Absent.

... but it's not a user friendly and intuitive way of setting the criteria, which is why All was introduced.

... (...but would also be the cause of bug reports).
...
  I can't come up with a scenario where I'd ever somehow would want a feature present in all tiles but being satisfied with it being provided by a tiny incursion somewhere in it: If a small incursion would be sufficient, it would probably be enough to have it anywhere in the embark, rather than demand it in every tile.
  I can make a case for demanding every tile to meet the criterion natively while allowing for incursions to differ as it might result in a smaller set of matches when you want the dominant part of your embark to match the criterion, but incursions vary a lot in size, so that's more an illusion of control that actual control.

In my view Absent and All are symmetric: Any presence invalidates Absent, and any absence invalidates All.

Just today I have told a colleague of mine one should not change the user experience without a really good reason - we discussed the changes he made to a filter in a list of possible options - of all the things :o :P
I really should heed my own advice and listen to your very strong arguments: strict "all" it is.
My gut feeling/intuition was that a less strict "all" might suit the users better.
Also it would not have required any changes... :)
Yes, I'm lazy I know :D

With your caching, I'd probably aim for a three step process:
- Process all MLTs in all world tiles.
- Process all incursions into all MLTs. However, it might be that it may be better to keep incursion processing for the interior MLTs in the first stage, as is done currently.
- Perform matching against all the fully processed MLTs. This step would be the only one needed for matching attempts after the first one.
Hehe, that's pretty much exactly what I've implemented, have a look here (https://github.com/bseiller/dfhack/tree/embark-assistant-index/plugins/embark-assistant)
If you want I can go into details - but right now I need to do some chores and get some sleep - I know I know sleep is overrated :D

PS:
Edit: My approach to deal with the incorrect top level data won't work: You need access to all the surrounding MLTs to process incursions, and attempts to process incursions as they become available would require the storage of both the native MLT results and the partial summary. Back to the drawing board...
Yeah, I had some fun with that situation as well - it added quite some complexity to the code. Also I store all 64 outer/edge mid_level_tile/mid_level_tile_basic (<= contains only data relevant for incursions) of a world tile inside region_tile_datum => north & south row +west & east column. The internal/intra world tile incursions are being processed parallel to the native data, the cross world tile incursions delayed until all neighboring world tiles have being processed - using counters and such to track the progress...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 13, 2020, 02:22:21 pm
I've just committed a PR for a fix of the bug (the world showing it was handy).

The fix isn't elegant. On the first pass the incursion criteria aren't checked at all (not that it should matter, as every tile is surveyed).
Once all tiles have been surveyed, all world tiles are checked for potential incursion resources from neighboring tiles. The keyword here is potential: at that location in the code the incursion direction info isn't available, so the code just checks all the neighboring MLTs saved for incursion checking and marks the resource as supplied by neighbors. When determining whether the world tile matches the high level criteria on the subsequent scans they're considered matched (for further checking) if the resource is available natively or might be provided by incursions as per the data collected above.
It would be possible to do a correct incursion checking by adding fields to the MLT info and populate them through a lighter incursion checking process, but it has the issues of a fair bit of additional messy code.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 15, 2020, 07:06:35 am
Good that the provided world was helpful!

I just looked at the changes in the PR hoping I could "backport" them easily to my version but alas the changes regarding the aquifers (the new separation in light and heavy) are too extensive to allow for an easy integration/merge.
The logical next step would be to migrate/update to the current develop branch (which I'll have to do eventually anyways) - but that would mean I'd have to adapt a lot of existing code, some of which isn't final/done yet. I worked on some larger projects were such an migration was done during the initial development phase - it never was a fun experience.
The main problem is bugs and being able to track if they have their origin in the newly developed code or in the merged/update base code. Without a stable feature baseline that can be used as a reference this can result in some extensive hide-and-seek-egg-hunt and it is just not Easter yet.
I'll have to ponder my options here a little more.

Also I'm wondering: Don't the other incursionable (?) characteristics (savagery, evilness, elevation/flatness, soil depth and biome) need the same special treatment as aquifer, sand and clay?
A quick test searching for biome1:"grassland_temperate" with the same world ("pocket_world_scarce") and a 4x4 area got me additional hits in the lower right corner (eastern part of the southern row) of the world tile at x:5,y:3 for example, also at x:6,y:3 (complete southern row) and at x:7,y:5 (western column, upper corner) with the index search.
If necessary I can provide exact coordinates or other additional data.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 15, 2020, 08:03:28 am
You're correct in that there's something broken with the temperate grassland search. However, it's not caused by missing incursion info as the whole 4*4 embark area in the lower right corner of the (5, 3) tile has temperate grassland as the native biome in each of the tiles, and even a single one ought to propagate it to the world tile level.

That does not mean that the rest of the incursion info shouldn't be made available, as I've got a sinking feeling that it should.

On to bug hunting...

Changing the baseline part way through is a pain, and I would only do it if my current work would largely have to be modified again to align with the new baseline. If I decided to shift the baseline, I'd probably port my changes from the modified older baseline piece by piece where each piece could be tested before moving the next one. If that wasn't possible because nothing works until everything's done I'd prefer to stick to the older baseline until it works (I might well move before the last bug was dealt with, but at least the general functionality should be there). If there was a risk that the work might turn out to have to be abandoned due to problems that couldn't be dealt with I'd stick with the older baseline simply to waste less effort before that unpleasant result was revealed.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 15, 2020, 09:15:01 am
However, it's not caused by missing incursion info as the whole 4*4 embark area in the lower right corner of the (5, 3) tile has temperate grassland as the native biome in each of the tiles, and even a single one ought to propagate it to the world tile level.
Hm, curious, yet all the additional matches seem to be located at one of the edges of the world tile, either x == 0 or y == 12 (or more general y == 16 - y_dimension)
Could it be an "one-off"?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 15, 2020, 03:38:12 pm
This got ugly: https://github.com/DFHack/dfhack/issues/1708 (https://github.com/DFHack/dfhack/issues/1708)

In addition to that, I do believe I've seen the number of matches shrink between the first and second pass, so yes, I think the rest of the incursion factors need to be taken into world tile level consideration as well.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on November 15, 2020, 05:18:51 pm
Oh my, reading the ticket sounds like quite an adventure down the rabbit hole.
One question of understanding though: Is the issue described in the ticket the reason for the biome1:"grassland_temperate" mismatch or was it an additional finding while debugging and affects only ocean biomes?
I'm wondering, because I'm currently running on dfhack 0.44.12-r2 and the new search code I added is indirectly using survey::high_level_world_survey and thus also DFHack::Maps::GetBiomeTypeWithRef and it correctly finds those matches, while the previously existing match code does not. So GetBiomeTypeWithRef can't be broken completely at least not for "grassland_temperate".
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on November 16, 2020, 04:36:37 am
GetBiomeTypeWithRef definitely works most of the time. It doesn't with the your original temperate grassland patch, and the tropical ocean boundary has changed, but I can't say how much has changed, beyond that it doesn't seem to be a major one. I spent a fair bit of time looking at temperate grassland, shrubland, and savanna without finding any obvious mismatch.
However, I came to the conclusion that it would be wasted time to investigate further, as that might give additional indications as to what has changed, but would do nothing to actually help solving the issue.

My guess is that there are a small number of minor adjustments that affect niche cases, plus a push to get the tropical ocean to reach further from the equator. A very possible change might be to have ocean turn tropical if it's in the "maybe" zone in addition to the "definite" one, and grassland might have had a parameter adjustment. There may well be other adjustments to things I haven't looked at.

I did compare the results with the Biome Manipulator that still uses a Lua implementation of the logic, and, as expected, it gives the same result as GetBiomeTypeWithRef, so it's not a matter if it being changed since or bungled up when introduced (which I have no reason to think would have happened, but it's still something that could be compared, resulting in the expected outcome).

In conclusion: The logic is not completely broken, but only suffering from minor dents and scratches, although you have to be wary about oceans (which I don't think would be a common search target anyway).

I believe I've seen cases of "found in the first search but not the second one" for grassland, so my next task will be to propagate the remaining incursion resources to the top level.
Title: Re: DFHack plugin embark-assistant
Post by: BoogieMan on November 16, 2020, 03:16:47 pm
This is awesome and extremely helpful, thanks for making it!

Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 02, 2020, 09:25:41 am
@PatrikLundell:
I think I found another issue while verifying the result of the min/max river-search:
If a world tile has at least 2 rivers with different sizes this will result in false positives/matches when searching for the occurring larger river size.
E.g.: A world tile has 1 medium and 1 minor river. Search for min-river:medium will return matches for all embark tiles that contain a river, even if it is only the minor river.
The reason for that is to be found here: matcher.cpp#L688 (https://github.com/DFHack/dfhack/blob/8548295fe5779b55046f13b57ec6d1f42c56605e/plugins/embark-assistant/matcher.cpp#L688) and here matcher.cpp#L1591 (https://github.com/DFHack/dfhack/blob/8548295fe5779b55046f13b57ec6d1f42c56605e/plugins/embark-assistant/matcher.cpp#L1591). The embark tiles themselves only know that they "have" a river, but not its size (river_present (https://github.com/DFHack/dfhack/search?q=river_present)).
As I had to calculate the river size from the max-min values (rivers_horizontal.y_max - rivers_horizontal.y_min / rivers_vertical.x_max - details->rivers_vertical.x_min) I could provide code.
Also the large world (region4) I've uploaded way back
I uploaded the save (http://dffd.bay12games.com/file.php?id=14584) and profiles I use for getting an idea how much memory it would take to "index" everything for a large world.
has at least one example (major river + stream) of this at x:166, y:61; starting from i:0, k:13 going to i:4, k:13.

Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 02, 2020, 12:19:58 pm
The game data only "knows" of at most one river per world tile. Other rivers may have their end point in a tile containing a "registered" river, thus joining it, but there's no info back to the top level about it, so there's no way to retrieve that info from the world tile. As you say, to check this properly you'd have to manually measure the river size at the MLT level (and, while doing that, you'll find that rivers change size gradually and thus can change from one size to the next one along its course, in the middle of a world tile).

Thus, it's an issue of an (over) simplified implementation of the check, but you're right in that it ought to be checked properly.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 03, 2020, 06:29:37 pm
argh  (https://github.com/PatrikLundell/dfhack/commit/c36fbe4c8b13a9eb71fd018108b9b09fb7eabe26)- stop being so fast  ;D
I'll never be able catch up if you keep this up :D
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 04, 2020, 04:48:59 am
If you stop digging up bugs I'll stop trying to fix them ;)

It's great that you're able to find so many bugs (although I'd wish there wouldn't be that many to find in the first place).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 15, 2020, 03:40:58 pm
Ups I think I did it again :D - there were some results related to incursions at world tile borders I couldn't wrap my head around and after adding more and more logging output I finally did some debugging, which lead to a realization almost instantly:
There is copy-paste-wrong-index issue here (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/survey.cpp#L584) and here (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/matcher.cpp#L477)
Every time i or k is used instead of fetch_i or fetch_k in one of the following terms in the big if-else-block
Code: [Select]
&survey_results->at(fetch_x).at(fetch_y).*_row[i]
&survey_results->at(fetch_x).at(fetch_y).*_column[k]
it potentially uses the wrong mlt to check for incursions.
This also means that fetch_i and fetch_k must be readjusted in the blocks where fetch_x and fetch_y are adjusted here (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/survey.cpp#L563) and here (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/matcher.cpp#L451)
similar to how it is done in survey::adjust_coordinates (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/survey.cpp#L1566)


Actually using adjust_coordinates might be the good solution.
Nevermind: values < 0 and > 15 are properly handled for fetch_i and fetch_k...  ::)
What do you think?

PS: survey::adjust_coordinates is not available in the context of matcher...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 16, 2020, 05:01:35 am
Yes, it looks like you're right. It can also be noted that the very last clause actually uses fetch_i and fetch_k.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 16, 2020, 07:04:48 pm
Ok, I think I've got one more...
All calls to
Code: [Select]
embark_assist::survey::region_type_ofin survey::translate_corner here (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/survey.cpp#L1759) and probably here  (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/survey.cpp#L1708) and here (https://github.com/PatrikLundell/dfhack/blob/9b53222932a831ae024d7b48763bf0889dcdeef9/plugins/embark-assistant/survey.cpp#L1708) as well should be using effective_x and effective_y like this
Code: [Select]
embark_assist::survey::region_type_of(survey_results, effective_x, effective_y, ...
I'm pretty sure about the first location with the 4 calls in a row, not so much about the other two locations, as my version of the translate_corner is older.
The error only manifests while going across world tile borders and if the corner_location is not embark_assist::defs::directions::Center but for example embark_assist::defs::directions::Southeast and the home_tile lies in the world tile east (south + south-east?) of the current one. So it should break for embark_assist::defs::directions::East and embark_assist::defs::directions::South as well.

I stumbled upon it as I mostly only use embark_assist::defs::directions::Southeast (or 8 in the old version) for corners and it did not behave symmetrically with embark_assist::defs::directions::Center (4) which resulted in incursions that only happened when looking from the receiving side in the south east...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 17, 2020, 05:47:51 am
Yes, you're correct again. It doesn't make sense to adjusted coordinates with unadjusted ones.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 24, 2020, 06:42:48 pm
Merry Christmas to everybody lurking around here!

So everybody is asleep and I'm trying to get this done before the year is over - 3 more criteria (freezing, syndrome rain + reanimation) then at least the search itself will be (mostly) done.
And I stumbled upon something strange - while surveying a 257x257 world I noticed that the temperature values in region_tile_datum seem to be mostly identical within a region_tile_datum (min_temperature[n] == max_temperature[n] => true for n = 0 - 9) for the whole world - I checked another 2572 world and it behaved the same, smaller worlds behaved different/correct(?) though, with a lot more distribution/differences between min and max temperature.
So I did some digging: The problem seems to be located around here in the function min_temperature (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/survey.cpp#L445).
It's my test world (http://dffd.bay12games.com/file.php?id=14584) with only one (south) pole => steps = 128; lat = 1 or lat = 0 which results in divisor 0.5 or 0.
As divisor is defined as uint16_t (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/survey.cpp#L396) all values below 1 get truncated to 0 directly which results in max_temperatur - 0 here (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/survey.cpp#L451).
Should divisor perhaps be a floating point value?
Or is there something else off with the formula for large (1292  + 2572) worlds if they have only one pole?

Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 25, 2020, 04:57:37 am
To start with: my brain is a bit sluggish today, and I have some difficulty understanding the problem. Thus, I may well bark up the completely wrong tree...

To start with the "easy" bit, i.e. how I believe DF's temperature variation works:
- On the coarse scale, DF's temperature variation changes linearly between the mid latitude and the pole as well as between the mid latitude and the equator, with the maximum variation happening at the mid latitude and zero variation at both the equator and the pole. This logic is the same regardless of whether you have a single or double pole world, but the single pole one has twice as many tiles to distribute that variation over.
- On the fine scale, there are steps caused by integer math, plus some weird cycle within same size segments of latitudes, and I don't know what the purpose of that lower level cycle is, just that it is present.
- For large worlds, this means there is no temperature variation at all for several world tiles near the poles and around the equator.

For your 128 step single pole test world, this means there should not be any temperature variation for the first two latitudes (and the two last ones), with a single degree variation happening for the next two latitudes. It's simply a case of an illogical choice of temperature variation logic and too many latitudes to smear out too small a variation over, so every variation value has to be shared over several latitudes. So, unless I've misunderstood the issue (which is entirely possible), I don't see any problem here.
Title: Re: DFHack plugin embark-assistant
Post by: Iä! RIAKTOR! on December 25, 2020, 04:51:20 pm
Why embark assistant don't differentiating of lairs? Mound and burrow are different in game code.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 25, 2020, 04:53:34 pm
Okay, I could be as well me imagining something, but lets look at the numbers of some examples.
The first 4 examples are the results with an unchanged function min_temperature, for the fifth example the type of divisor was changed to float, as well as the expression
Code: [Select]
divisor = (64 / steps * lat);to
Code: [Select]
divisor = (64.0f / steps * lat);
What you see below is the distribution of min-max temperatures below-equal to zero/above zero for all embark tiles. Adding the number of entries for both min and both max row results in roughly the number of total embark tiles (=> 3. column). The delta between the sum and the actual number of embark tiles is caused by incursions.

Now see how "random" the distribution is for the first (pocket) and the second (small) example.
And now compare that to the distribution of the third and fourth example, both 2572. Both "min <= 0" and "max <= 0" have the same number of entries, as have "min > 0" and "max > 0". That seems odd, doesn't it?
For the fifth example (changed function min_temperature) the distribution looks much more like for the first and the second.
The reason is, that values between 0 and 1 are possible for divisor, which results in a larger variation.
This looks "right" for me - of course I have no clue if it really is correct.
What do you think?

1. 172, pocket - # embark tiles 73.984
range# ∑ # min/max
min <= 0 27908
min  >  0 48355 76.263
max<= 0 10583
max >  0 64243 74.826

2. 332, small - # embark tiles 278.784
range# ∑ # min/max
min <= 0 97967
min  >  0 188173 286.140
max<= 0 32768
max >  0 248539 281.370

3. 2572, large 1 - # embark tiles 16.908.544
range# ∑ # min/max
min <= 0 2243169
min  >  0 14758891 17.002.060
max<= 0 2243169
max >  0 14758891 17.002.060

4. 2572, large 2 - # embark tiles 16.908.544
range# ∑ # min/max
min <= 0 1980576
min  >  0 15013574 16.994.150
max<= 0 1980576
max >  0 15013574 16.994.150

5. 2572, large 1 - float divisor - # embark tiles 16.908.544
range# ∑ # min/max
min <= 0 7843764
min  >  0 9387251 17.231.015
max<= 0 2243169
max >  0 14758891 17.002.060
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on December 25, 2020, 05:03:31 pm
Why embark assistant don't differentiating of lairs? Mound and burrow are different in game code.
Are you talking about on the local map when embarking? What DFHack version are you using? 0.47.04-r4 (released yesterday) adds support for this (PR (https://github.com/DFHack/dfhack/pull/1713), changelog (https://docs.dfhack.org/en/0.47.04-r4/docs/NEWS.html#misc-improvements))
Title: Re: DFHack plugin embark-assistant
Post by: Iä! RIAKTOR! on December 25, 2020, 05:53:11 pm
Why embark assistant don't differentiating of lairs? Mound and burrow are different in game code.
Are you talking about on the local map when embarking? What DFHack version are you using? 0.47.04-r4 (released yesterday) adds support for this (PR (https://github.com/DFHack/dfhack/pull/1713), changelog (https://docs.dfhack.org/en/0.47.04-r4/docs/NEWS.html#misc-improvements))
Thanks! I'll update my dfhack soon.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 25, 2020, 06:16:38 pm
The reason the lairs weren't differentiated originally was that the DFHack values weren't enumerated and organized as integer values associated with vague and, I think, not entirely certain descriptions, so it wasn't clear how many types of lairs there were or in which way they differed.

On to temperature:
The formulae for determining the temperature variation were matched to measured temperatures over the year at various latitudes in variously sized worlds and eventually managed to correctly predict which day and tick the temperature would change (as reported by DF's data structures). All those temperatures are integer numbers. The presence of a fudge factor in some of the formulae is an indication that those formulae (at least) aren't entirely correct.
However, it may be that the code should reshuffle the factors to ensure the correct result, i.e. "divisor = ((lat * 64) / steps)". In pure math the order of the division and multiplication terms doesn't matter, but it does with the imperfect emulation of math performed by computers.

Max temperature is the "official" temperature of the world tile (i.e. the value in the world tile data), while the min temperature is the max temperature - the maximum variation (which lasts for a single tick in some cases), so the max temperature variation is completely dependent on the official world tile temperature, which, in its turn, is dependent on latitude, elevation, and the temperature parameters for world gen.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on December 26, 2020, 05:41:14 pm
Max temperature is the "official" temperature of the world tile (i.e. the value in the world tile data), while the min temperature is the max temperature - the maximum variation (which lasts for a single tick in some cases), so the max temperature variation is completely dependent on the official world tile temperature, which, in its turn, is dependent on latitude, elevation, and the temperature parameters for world gen.
Yes, I saw how min temperature was derived from max temperature and that in turn was taken from region_map_entry and transformed.

Reordering the expression to divisor = ((lat * 64) / steps) as suggested results in the below distribution of min temperatures - which also looks much more random / natural and similar to the results of the fifth example.
I'm currently pushing to get the search criteria done (2 remaining, just finished "freezing"), otherwise I would be happy to do some science to evaluate the fitness of the changed divisor expression. If I can wait a little longer I can take care of it then.

6. 2572, large 1 - divisor = ((lat * 64) / steps) - # embark tiles 16.908.544
range# ∑ # min/max
min <= 0 7506116
min  >  0 9729380 17.235.496
max<= 0 2243169
max >  0 14758891 17.002.060

PS:
Also I have an idea on how to proceed (as we have discussed  (http://www.bay12forums.com/smf/index.php?topic=169634.msg8212121#msg8212121)some time ago) that I would like to run by you but first I want to get the criteria done and fix two more hopefully little issues.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on December 27, 2020, 05:19:00 am
Correcting the order of the terms should give a result very close to that of forcing the calculations to be performed using floating point math and then truncating the result to an integer one, and it may be that the results are identical for this value space, but you can't trust it would be without a careful analysis (where "careful analysis" can be an exhaustive comparison of all possible results). I assume you've seen floating point values of the type 1.99998 when the mathematically correct value was 2, but truncating it to integer would nevertheless result in 1...
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 03, 2021, 04:43:29 pm
Happy new year everyone!

First things first:
I assume you've seen floating point values of the type 1.99998 when the mathematically correct value was 2, but truncating it to integer would nevertheless result in 1...
Actually I saw a natural value of 0.5 for divisor which was rounded up (ceil) to a 1 after being multiplied with 0.75 here (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/survey.cpp#L451) resulting in
Code: [Select]
max_temperatur - 1
And now: Good news everyone!
I finally finished the last query (in the old version) which was reanimation.
While comparing the results of the matcher with the results of the index for the "Reanimation or Thralling" option I found something curious:
At first I implemented this as strict OR/XOR as in "either Reanimation or Thralling" but that seemed to return not enough results, after changing the implementation to the broader AND/OR as in "Reanimation and/or Thralling" (=> ||)  the results matched perfectly.
So my question is: Is the implementation for embark_assist::defs::reanimation_ranges::Any (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/defs.h#L315) by intention broad and the wording of the option in the UI could be made clearer if changed to "Reanimation and/or Thralling" as it also contains all matches that have both reanimation and thralling or should the implementation be more strict and thus represent an exclusive OR/XOR as in "either Reanimation or Thralling" which would require the logic to change?
The condition here (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/matcher.cpp#L2019) and here (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/matcher.cpp#L2448) and here (https://github.com/PatrikLundell/dfhack/blob/0b7ab90d3d8987acac62971db8f42ba55f52567d/plugins/embark-assistant/matcher.cpp#L1301) as well as
Code: [Select]
!tile->reanimating_possible && !tile->thralling_possiblewould need to be changed to
Code: [Select]
!tile->reanimating_possible != !tile->thralling_possibleor easier to read
Code: [Select]
tile->reanimating_possible != tile->thralling_possible
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 04, 2021, 05:28:34 am
My statement on the unsuitability to mix floating point math with integer math was intended to be general, not referring to this specific code. Floating point results end up near the mathematically correct result (most of the time: there are exceptions), but can end up both above, spot on, and below. Applying truncation or rounding up to such values can give the wrong value, where "proper" rounding might work.

The intention of the "Any" value for reanimation is "at least one of them", so it's good your results reflects that. If I'd intended to say exactly one of them I'd probably have called it "Either". However, I agree the UI would be clearer with "and/or".

I don't think there would be any reason for a player to want one or the other type of reanimation but exclude both of them, while I can see that players may want to ensure a challenge by requiring at least one of them.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 14, 2021, 05:18:34 pm
My statement on the unsuitability to mix floating point math with integer math was intended to be general, not referring to this specific code. Floating point results end up near the mathematically correct result (most of the time: there are exceptions), but can end up both above, spot on, and below. Applying truncation or rounding up to such values can give the wrong value, where "proper" rounding might work.
Ah, okay, now I see. Yes, of course, you are absolutely right.

The intention of the "Any" value for reanimation is "at least one of them", so it's good your results reflects that.
Good, so I'll leave it as is.

If I'd intended to say exactly one of them I'd probably have called it "Either".
I wanted to be sure, as I experienced first hand - also with my own code in multiple projects - how software grows and changes gradually until its current internal logic no longer fits the original designations of variables, classes or display labels that were named under the impression of their initial creation - a process often imperceptible for the one perpetrating it, kind of a temporary syndrome similar to mental blindness from staring to long on to something, the last days have been full of that at work actually. :)
It takes a lot discipline to stay ahead of that, notice it and change names accordingly.

I don't think there would be any reason for a player to want one or the other type of reanimation but exclude both of them, while I can see that players may want to ensure a challenge by requiring at least one of them.
As I only accidentally have encountered reanimation and thralling - which ended badly quit fast - I really wouldn't dare to guess what players that are actively looking for it might want :D
So I'll trust your judgement.

Okay, there are 2 more things I'd need to fix before merging makes sense, but I have this idea about how to make the merging/migration to the latest version of the code both easier and safer (if for any reason all/most of my work won't make it into the plugin):
I will open 3 or 4 pull requests against your latest branch (https://github.com/PatrikLundell/dfhack/tree/embark-assistant/plugins/embark-assistant).
The first one contains a minimal change that should speed up the search without actually changing the logic.
The second one will change a little more code saving a lot of memory again without really changing any logic.
The third and if needed the fourth would both be an actually refactoring that would make the merging easier by reducing the amount of duplicated code at those places where I had to add to the code the most.

Apart from that I have to ask someone (you or lethosor?) how to handle the external dependency CRoaring/Roaring Bitmaps that I used as-is by putting the 3 files (roaring.h,~.hh,~.c) alongside the sources of embark-assistant.
Those files might make the linter scream also I'm unsure if it is fine to add external dependencies like that...
I'm willing to change the files to make them comply to the rules if necessary even if this means any future update of CRoaring brings some additional overhead.
Also some (performance) tests on Linux would be good.

Perhaps the most important question: Would you be okay with a so fundamentally changed version of the plugin (https://github.com/bseiller/dfhack/tree/embark-assistant-index/plugins/embark-assistant)?
I actually never asked that question as I never have been really sure that it could be done (there is still a chance that some "minor" detail brings it all down).
I'm willing to co-maintain with what I know, added and changed, if that makes a difference.
But there are quite a lot of DF/dfhack internals that are beyond me.
And the time I actually can spend on this is limited.
So?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 15, 2021, 05:55:29 am
I'm certainly aware of the process of things slowly creeping away from the original intent...

I don't mind reanimation much, but I've kept away from thralling. However, if you're willing to face thralling then reanimation isn't that much of an additional problem. People who'd search for thralling and/or reanimation are looking for a challenge.

I'm not sure how to handle the Roaring stuff. @lethosor is probably the person who can make the decision about that, but my gut feeling is that it would be better to have that as a separate addition to the DFHack code so it can be used elsewhere. Regardless, the copyright and usage conditions of the code has to be compatible with that of DFHack.

If I had been opposed to changing the plugin I would have told you so before you wasted a lot of time on the task. I have to admit I didn't think it would work, but if it does I don't see why improvements should not be made.

When it comes to merging the work, I don't know what the best process is. So far I've never merged anything but the DFHack develop/master into my branches (and then by pulling those into my local copy and then pushing it up to the branch). Usually pull requests are made against DFHack develop, and I don't really know how to handle it through my branch. The problem is that Git and I are at odds, so I can perform a very narrow set of actions with a limited risk of screwing (or be screwed) up. I don't even know how to do a diff to compare code, something that's easy in sensible version control tools such as e.g. Subversion). Advice from someone(s) experienced in this kind of Git activity would be welcome.

I'm not using Linux (or any of the other -ux variants), so I can't help with that testing.

When it comes to maintenance of the code my participation depends on the extent to which I understand what the code does.
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on January 15, 2021, 08:35:46 pm
I think the multiple-PR merge strategy you mentioned would make the changes easier to digest - large merges can sometimes take some effort to go over. The current diff (https://github.com/DFHack/dfhack/compare/develop...bseiller:embark-assistant-index) looks a bit large to me, but I see things split into commits well enough that it should be easier to review that way. GitHub also says there are merge conflicts, although those aren't easy to see through the web UI, so I'm not sure how extensive those are.

Merging into DFHack's develop branch is probably the way to go here, assuming it's up-to-date with PatrikLundell's latest changes.

I'm not completely sure what your changes do at the moment, mainly because I'm not particularly familiar with the plugin internals, so PatrikLundell would be a better person to make an assessment in that regard. I can do some basic testing on Linux (or more complicated testing with instructions).

Assuming you're referring to https://roaringbitmap.org/ - it appears to be Apache 2-licensed, which should be fine, although we don't currently have any dependencies using that license, and it wouldn't work particularly well with the current formatting of our license documentation page, so we might need to rework that (but I can handle that). I would also agree with PatrikLundell that it shouldn't be part of the plugin itself - it looks pretty easy to include as a dependency, and its readme (https://github.com/RoaringBitmap/CRoaring) even advertises that it can be included as a subdirectory, so I'm thinking the "depends" folder would be a good place for it. That's something that I could help with once you get to the point of merging it in.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 16, 2021, 05:35:33 am
There's nothing outstanding in my branch, as the latest PR has been merged, so that part shouldn't be an obstacle. I'll review the commits to the best of my ability.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 16, 2021, 06:11:16 pm
@lethosor:
Thank you for chiming in so fast - it would have taken me another few days to address you with my questions.
And thank you very much for taking the time to get into some of the details already!

Actually my branch is not up-to-date with PatrikLundell's latest changes as I did not have the capacity to implement the adaptations and continuously merge the new features.
That explains the merge conflicts we see here (https://github.com/DFHack/dfhack/compare/develop...bseiller:embark-assistant-index).
My plan is to bring over some smaller, standalone improvements I discovered during development via separate pull requests into the develop branch by going through PatrikLundell's branch so he can review everything before it gets pushed/pulled into the main repository. After that I would fork PatrikLundell's development branch (https://github.com/PatrikLundell/dfhack/tree/embark-assistant/) again, merge my work into it and finally add the search criteria (like tree density) that have been added since I started developing.
That seemed to be the proper way to do this to me, as his branch would stay the master/single point of truth at all times.
Also there might be a phase of consolidation before the plugin is really ready for the dfhack develop branch. To allow for easy bugfixing of the current version of the plugin a separate branch for the new stuff might be useful.
But I'm not an experienced git/github user myself so I'll happily take any advice on how to approach this.

Assuming you're referring to https://roaringbitmap.org/
You're correct - I'm using their Amalgamation/Unity Build (https://github.com/lemire/CRoaringUnityBuild) which made the integration easy.
One reason to keep the dependency local to the plugin might be this have been the missing namespace (https://github.com/RoaringBitmap/CRoaring/issues/197) - oh they fixed it, but the fix hasn't been propagated to the Unity Build yet, just saw that myself right now.
Well, okay - that was the one point that made me feel uneasy about putting CRoaring into the global dependency scope for all of dfhack. With that gone I'm very much in favour to treat it as any other external dependency, especially as it could be used by everyone that way, even if it is kind of a niche thing.

I'm not completely sure what your changes do at the moment, mainly because I'm not particularly familiar with the plugin internals, so PatrikLundell would be a better person to make an assessment in that regard.
If desired I could do a little write-up with the core concepts behind my additions - putting it alongside the code as a little readme might help others that look into the plugin in the future.
Also getting feedback on my ideas and design decisions after spending such a long time on it would be nice :)
Apart from my thousand questions about details and DF world data internals I tried to not additionally bother PatrikLundell with my thought process as it could have been for naught.

I can do some basic testing on Linux (or more complicated testing with instructions).
That would be much appreciated!
Runtime performance/speed on Linux is the one thing that could make it necessary to change part of the implementation:
I'm using std::async (https://en.cppreference.com/w/cpp/thread/async) here (https://github.com/bseiller/dfhack/blob/c9fc554f9362cc8163ebfa3a8c2ec47309f317bc/plugins/embark-assistant/survey.cpp#L1979). Which on Windows internally uses thread pools. But I'm not sure that is the case on Linux too by now (https://stackoverflow.com/questions/14351352/does-asynclaunchasync-in-c11-make-thread-pools-obsolete-for-avoiding-expen).
And if a thread pool became necessary I really could use some hints on how to use the existing tthread (https://github.com/DFHack/dfhack/tree/develop/depends/tthread) dependency.
Before going for std::async I had a look at tthread and where it is being used in dfhack but it didn't make much sense then. Might be different now though.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 16, 2021, 06:46:19 pm
Well, actually, develop is the "master" for DFHack development (with "master" basically being the latest release, and thus the stable version). Thus, basing your fork off of "develop" would be the way to go (that way the rest of the code would be up to date as well). Once your fork's pull request has been merged, you can refresh your fork with the latest from develop (which shouldn't contain any changes to the Embark Assistant code, but may refresh other things), update it with the next set of changes, and issue a new pull request.

Actually, the above is a bit of a simplification, as there are three, not two versions involved:
- On your local machine, create a fork off of develop
- Do the work
- Push it to Github
- Get comments and discussions, update the local copy and push to Github.
- Repeat until "done"
- Make a PR
- Possibly get more comments, in which case the local copy is updated and pushed to Github, which automatically amends the outstanding PR.
- Get the PR accepted and pulled into develop.
- Refresh the local copy from develop (again, typically only gets the background up to date)
- Do the work again
- etc.

If I understand it correctly, the first PR won't have any Roaring Bitmap code in it (local variables rather than .at() functions everywhere, and similar things), and so can be started immediately, while the one(s) relying on it will have to have it in place to be referenced, and so have such a PR accepted before that work can be done.

It can be noted that others have touched the Embark Assistant code without me being involved in the past, such as when the biome determination code was factored out, so my branch isn't the master.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 17, 2021, 08:06:47 am
It can be noted that others have touched the Embark Assistant code without me being involved in the past, such as when the biome determination code was factored out, so my branch isn't the master.
Ok, that is something I never knew or noticed.
You being the most vocal and present in the embark-assistant thread I assumed it all runs through you for this plugin :)
And all my other assumptions are based on this one.
But I was aware of another "level" concerning decisions about the whole of dfhack, like global dependencies and the like.

If I understand it correctly, the first PR won't have any Roaring Bitmap code in it (local variables rather than .at() functions everywhere, and similar things), and so can be started immediately, while the one(s) relying on it will have to have it in place to be referenced, and so have such a PR accepted before that work can be done.
You are correct in your understanding that the first few PRs won't have any references to Roaring in them at all - but at least the first 2 or 3 won't be a classic refactoring either, but smallish changes that should improve memory consumption or performance.
The refactoring comes after that and - yes again - as a preparation for the big haul.
And if you see any changes in the PRs that need clarification, more or better comments or another name for a structure than fire away.
Also I'll try to keep the changes/PRs as consistent as possible to allow for easy review and focused discussions.

Well, actually, develop is the "master" for DFHack development (with "master" basically being the latest release, and thus the stable version). Thus, basing your fork off of "develop" would be the way to go (that way the rest of the code would be up to date as well). Once your fork's pull request has been merged, you can refresh your fork with the latest from develop (which shouldn't contain any changes to the Embark Assistant code, but may refresh other things), update it with the next set of changes, and issue a new pull request.

Actually, the above is a bit of a simplification, as there are three, not two versions involved:
...
Mostly see the first paragraph about me having a faulty base assumption and not verifying properly early on which is the leading repository.
And thanks for the explanation about the workflow - on a theoretical level I'm aware that it can be done and is done like that in many public (OSS) projects.
Its the practical part of the PR process that is pretty new to me (I think I've done it twice in other OSS projects), I'm working with SVN on a daily basis and we do our "code reviews" and integration a little differently.
But I'm sure that we'll both manage just fine!
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 18, 2021, 01:56:22 pm
I've created the the first PR (https://github.com/DFHack/dfhack/pull/1755).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 28, 2021, 06:06:21 pm
I started with the refactoring branch (https://github.com/bseiller/dfhack/tree/ea_refactoring).
Will turn it into a draft/WIP PR in the next few days and notify you, so you can start reviewing at your leisure while I add some more.
There may be some small performance improvements mixed in, which will be covered by the existing changelog entry.
I'll explicitly point them out anyway, as they still deserve some more attention.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 29, 2021, 05:43:46 am
In retrospect, I think it would have been better if I'd implemented the improvements you've made so far when you pointed out the issues rather than wait for you to do them, as I now don't think you doing them would mean less merging work and conflict resolution than if I'd done them earlier (and thus gotten them released earlier). I guess that's a lesson for the future.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 29, 2021, 06:03:18 pm
In retrospect...
Just to make sure I understood correctly - as it is late: You think the total effort is larger doing it the way we do it now? That is by "delayed" PRs which have to be reviewed and then merged which might produce merge conflicts?
If that is what you mean, than yes, it might have been less effort doing it right then and there.
But, at least for the effort on my side I can say this: I'm fine with it as it gives me the chance to learn how to use git/github properly - also it gives us the opportunity to discuss the changes more directly, closer to the code. Doing so here in the forum feels complicated sometimes.

In hindsight I would have liked to stay in sync/up to date with your development branch or at least with the develop branch of dfhack. That would have spread the merge effort evenly over the complete development time. But I was so very busy figuring out if the index approach actually would work, so I kind of couldn't be bothered with merging, also git was an even stranger beast then.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 30, 2021, 06:01:32 am
Not quite. I think it would have been a very slightly larger effort to add the improvements as they were discovered and then merge your "real" changes than doing it the way it's done now (because there would probably have been some merge conflicts between how you implemented it and how I did it), but with the benefit of getting the improvements out to the users a year earlier.

I'm no fan of git: it's a shotgun with a default aim at your feet, a very sensitive trigger, no safety catch, and a confusing and unhelpful tangle of obscure commands and switches.

I would probably have tried to merge changes as long as they were small and easy to do but stop when it became complex to do them (incursion introduction). At that time I'd concentrate on the proof of concept, with an eye to what effect incursions would have, get the caching to work, and then merge in incursions and adjust the caching to work with that. However, that's with some basic knowledge of git (but still probably done with a backup of my code just in case git screws me over).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 30, 2021, 05:22:20 pm
Not quite. ...
Yes, I see. Had I known what I know now and found a easier and faster way to do it while getting the caching out there to the users, that would have been good.
But a lot of this was about experimenting and discovery, so even without git...

I'm no fan of git: it's a shotgun with a default aim at your feet, a very sensitive trigger, no safety catch, and a confusing and unhelpful tangle of obscure commands and switches.
It is indeed a very mighty weapon, not for the faint of heart. I consciously try to tread lightly and sometimes create branches just to test a chain of commands. In the end all question have an answer somewhere out there, but sometimes I don't know what the question is :D

Actually there is one question I know how to ask by now:
Comparing this line (https://github.com/DFHack/dfhack/blob/84eaf0414870826fb6a925794cf1a39c881f80d6/plugins/embark-assistant/survey.cpp#L596) with those two (https://github.com/DFHack/dfhack/blob/84eaf0414870826fb6a925794cf1a39c881f80d6/plugins/embark-assistant/survey.cpp#L559) - shouldn't it be
Code: [Select]
world_data->region_map[adjusted.x][adjusted.y] here  (https://github.com/DFHack/dfhack/blob/84eaf0414870826fb6a925794cf1a39c881f80d6/plugins/embark-assistant/survey.cpp#L559)and here  (https://github.com/DFHack/dfhack/blob/84eaf0414870826fb6a925794cf1a39c881f80d6/plugins/embark-assistant/survey.cpp#L560)as well?
If so I can fix is within my current branch to keep thinks simple.

And lastly should we move this specific kind of question into tickets over here (https://github.com/DFHack/dfhack/issues)?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 31, 2021, 05:01:17 am
Yes, you're correct. It should be "adjusted." there as like in all of the surrounding code, so yes please, take care of that one.

Personally I find it easier to discuss these issues here. I don't check issues regularly, and do it only when I'm engaged in DF structure research (or if I received a notice of an issue I should be aware of). My take is that I'd use a thread dedicated to the plugin/utility firstly if there is one, and write an issue if there isn't one or if it's unclear where the problem is. It can be noted that the DFHack thread is a general thread, not one dedicated to a specific thing, so I agree issues are better in that case to ensure things don't get lost.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 31, 2021, 07:50:49 am
Yes, you're correct. It should be "adjusted." there as like in all of the surrounding code, so yes please, take care of that one.
Will do.

Personally I find it easier to discuss these issues here.
Fine by me.

I think there is one more or something is off somehow somewhere else:
Please compare this line (https://github.com/DFHack/dfhack/blob/84eaf0414870826fb6a925794cf1a39c881f80d6/plugins/embark-assistant/survey.cpp#L495) and this one (https://github.com/DFHack/dfhack/blob/d2f3ec607667c0b42e1307f94a801f58cfaa52db/plugins/embark-assistant/survey.cpp#L1076) with this one (https://github.com/DFHack/dfhack/blob/d2f3ec607667c0b42e1307f94a801f58cfaa52db/plugins/embark-assistant/survey.cpp#L979).
By using the
Code: [Select]
world_tile pointer it also uses x and y instead of "adjusted."
Should I adapt that one as well or is there an underlying reason I don't see?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on January 31, 2021, 01:21:49 pm
I don't quite follow what you're after. The two first references seem to be to two different versions of the same code. The is_brook flag check has to be for the current world tile, as that property is independent of the biome, and so cares only for which world tile the tile resides in.

The third reference is to biome related code, and so needs to use adjusted coordinates.

Thus, unless I've missed your point (entirely possible) the code shouldn't be changed.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on January 31, 2021, 04:16:13 pm
The is_brook flag check has to be for the current world tile, as that property is independent of the biome, and so cares only for which world tile the tile resides in.
The third reference is to biome related code, and so needs to use adjusted coordinates.
Ah - that was what I meant when I wondered if there is a reason for the difference.
So, just to make sure there is no misunderstanding: To retrieve the proper value for the "is_lake" flag (https://github.com/DFHack/dfhack/blob/d2f3ec607667c0b42e1307f94a801f58cfaa52db/plugins/embark-assistant/survey.cpp#L979) the coordinates have to be "biome adjusted", but for the "is_brook" flag that is not true and the none-adjusted coordinates must be used, yes?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on February 01, 2021, 03:25:51 am
Correct.

To be overly explicit (not that I think it's really needed):

- "is_lake" is a biome type property and it's used to determine soil depth, which is also tied to the biome. The biome is tied to a host world tile, which may or may not be the current one.
- "is_brook" applies to all MLTs in the world tile, regardless of whether the biome of those are tied to surrounding world tiles or not (it only has any effect on the MLTs that actually have a watercourse in them, of course). That should mean that any watercourse joining "the official" brook watercourse in that world tile should also be a brook, even if it wasn't upstream, although I haven't investigated if that conclusion is correct.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 05, 2021, 03:04:29 pm
Just in case someone is wondering: I'm still here.
I took a little sabbatical, as I needed some time to actually play a game or two for a change :)
And then 3 weeks ago I took the time to give the change concerning the inorganic vectors (https://github.com/DFHack/dfhack/pull/1771#discussion_r579720715) a go.
Having tested it originally in 0.47.04 made it look like it was worth the effort performance wise. But upon migrating the setup to 0.47.05 the performance gain is not that big anymore, like 4 seconds for a large world instead of around 7 as measured originally.
And that is for the code itself being measured in place. Testing in windowed mode the complete search took just a long as before, those 4 seconds somehow evaporated into thin air. And also taking into account that it can be quite fickle to reliably measure a difference of just 4 seconds on a regular desktop pc repeatedly... Only in fullscreen mode those 4 seconds translated into a net gain at the end of a search, strange that one.
Plus 0.47.05 seems to run faster as a whole, so I further doubt this change brings much to the table.

@PatrikLundell: What do you think? Are 4 potential seconds worth the trouble of a PR?

PS: Looking at my explanation in the PR again I'm tempted to give it another go either with std::vector<char>  and/or with std::memset just to make sure I'm not missing something (less) obvious. I'll report my findings.

Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 06, 2021, 03:07:18 am
It's better for the long run to take pauses to recharge batteries once in a while, and the current mess doesn't exactly help the spirits.

I suspect the oddities for the windowed mode is just that: an artifact introduced by the OS.

I think 4 seconds is borderline, but not useless, so it would be useful if it was introduced, but I wouldn't be upset if you considered it to be too much effort for too little gain (annoyingly inconclusive, but I feel taking a definite stance isn't the right action here).

I'd rather follow lethosor's advice and use uint8_t instead of char.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 16, 2021, 10:43:02 am
I'd rather follow lethosor's advice and use uint8_t instead of char.

Ah, I wasn't planning on disregarding his advice, I just wanted to see if another approach would result in a more favorable outcome.
And after experimenting around for 30 minutes and reading for 2 hours I learned something new:
- Compilers aren't as smart as we both wish them to be
https://blog.royalsloth.eu/posts/the-compiler-will-optimize-that-away/
- And sometimes you really have to trick them to get them to get it right:
https://travisdowns.github.io/blog/2020/01/20/zero.html

And at last: std::memset is much faster for a std::vector<POD> than std::fill, but std::vector<bool> is a special case as we already knew...:
https://stackoverflow.com/a/1665038/167865

=> Using std::memset on a std::vector<uint8_t> takes a total of 2 seconds, which is a good speedup in my book...
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 16, 2021, 11:31:09 am
Experimenting is good, and two seconds for a rather minor change of the code is good as well.
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on May 30, 2021, 02:18:47 pm
Hi there. I'm finally getting back into Dwarf Fortress after 2 years and I've downloaded the latest LNP from PeridexisErrant but keep having issues with the Embark Assistant Crashing. I have done fresh installs. Disabled the TWBT and generated new worlds. Full Screen and Windowed. It lets me get to the list of options you can choose from but when I add a filter and hit F it just freezes then crashes

I have managed to get it to work about 1 in every 10 times. But I cannot seem to narrow down what is causing it to crash the game. I've tried running a normal embark search first and then ran the embark assistant afterwards and that was the only times I managed to get it to work but it is not consistent most of the time it will present a black screen or just freeze on the filters page.

Any advice would be greatly appreciated.


Edit: more specific info
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 31, 2021, 02:09:24 am
Any advice would be greatly appreciated.
Hm, that sounds ominous.
How is your system equipped memory-wise?

Can you provide us with a zipped download of your region/world save?
Like over here Dwarf Fortress File Depot (https://dffd.bay12games.com/) for example.
That would allow us to check firsthand.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 31, 2021, 02:51:21 am
@Deuslinks: What do you set the filter to (including the embark size), and what's the size of the worlds you've used (if it's the largest ones there could definitely be memory issues)?

I suspect the problem is linked to something in the filter profile, so knowing what you search for could help us reproduce the problem.
Since you say "worlds" in plural, I guess you've tried several worlds, but it certainly won't hurt error reproduction if we get both the profile (i.e. what you've searched for) and a world it crashes in, although my gut feeling is that it may happen to most worlds when that criterion or group of criteria is used.
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on May 31, 2021, 04:20:30 am
Hi  RedDwarfStepper and PatrikLundell

Here are the links for two regions both of them crashed when searching

https://dffd.bay12games.com/file.php?id=15549 

Size Large
History Medium
Civ Very High
Beast High
Savagery Low
Minerals Frequent


https://dffd.bay12games.com/file.php?id=15550

Size Medium
History Medium
Civ  High
Beast High
Savagery Low
Minerals Frequent

My PC has 32 Gig Ram and a Nividia RTX 3070 with 8 gig inbuilt. I monitored it on the task manager and dwarf fortress gets up to about 1.5 gb on ram usage

For the Filters I left the embark size as default so 4by4. Typically my first filter is for 1/2 Towers and then I run it and then if it works for that first filter I am able to add all the others I want.

The second region is one I created this morning and have tried running a filter just for Elves and it crashed 


Thanks for helping with this

Edit: I managed to have a bit of luck this morning and have managed to get it to work twice I've needed to search for something with the original filter on the embark screen so set Clay to yes let that run once it is done hit esc to view the results and then go into the embark assistant and search for 1 tower and it has worked on both maps. But if there hasn't been that many people reporting the issue it may be my system
Title: Re: DFHack plugin embark-assistant
Post by: clinodev on May 31, 2021, 06:35:11 am
I don't have a proper bug report, but I can say I saw a streamer get a CTD using embark-assistant. I assumed it was some particularity of their setup, but it would be on the current DFhack release.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 31, 2021, 07:50:35 am
Hm, frustrating.

I tried the second world provided by Deuslinks changing the embark size to 4*4 (mine's set to 3*3 as default) and elven presence, which worked as without any issues. I've tried to export the parameters of the world and regenerating it and then searched it with the same parameters (because DF sometimes generates different worlds from the same world gen data depending on whether it's a fresh start or a game has generated something previously, so there are some seeds that aren't reset full), but searching both the generated world and the original one again worked without problems.
I then tried the first world, again with a 4*4 embark, but searching for min 1, max 2 necro towers. Again, no crash for me.

Boogieman reported the same kind of issue in the Starter pack thread, but hasn't provided any additional details, so there's something, somewhere affecting at least 3 different people. Whether the issue lies in this plugin, something else, or a combination of factors is unknown, and without a way to reproduce it where it can be investigated it will be hard to track down.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on May 31, 2021, 03:00:56 pm
Hi RedDwarfStepper and PatrikLundell...
Thanks for that Deuslinks!

@PatrikLundell: If it really is system-dependent we probably won't be able to reproduce the crash with our systems.
But throwing out a wild guess: It could be one of the Microsoft Visual C++ YYYY Redistributables. On my system there are 15(!) different versions installed, ranging from 2005 to 2015 alternating between x86 and x64...
Or as it does not happen every time it might have something to do with how some memory area is (un)initialized, which could depend on which other programs are running or what has happened in the memory of the DF process beforehand.
Still pretty hard to debug.
But if is modification of the starter pack itself or the config of the installation we might catch it with a zipped download of the installation minus the world saves and minus the folder "\LNP\utilities\" (so big!) we have already.
What do you think?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on May 31, 2021, 05:51:00 pm
No, I don't think the chance of catching it on a system where it doesn't happen when looked for are high, and, unfortunately, I don't think the installation is the culprit, but I might be wrong. The best odds are probably for some victim to be able to debug it, preferably with a locally compiled DFHack (so debug symbols are available).

However, the only thing lost trying a zipped installation that doesn't reproduce it is some time...
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 01, 2021, 05:45:30 pm
dumb question incoming: Won't "any" debug-dll - even one we built - give more details than the release version?
less dumb question: Have you ever worked with "Dr. Watson"? It should be available on most Windows systems and could allow us to get a crash log...
Or this might work as well:
https://docs.acrolinx.com/kb/en/how-do-i-capture-a-process-dump-of-a-crashing-application-for-support-13731081.html
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 02, 2021, 02:25:09 am
I'd expect a DLL built with symbols would potentially give more info to someone who's hooked up a debugger to DF, yes, but without a debugger I'd expect the same crash and no info, but I can't say with certainty as I haven't tried.

I've never used Dr Watson. However, I've enabled crash dumping in the past (several years ago), for something (I've done it for DF, and found Toady can't use them, but I haven't used them myself). If a crash dump is generated, I'd expect a DLL with symbols to be more useful than one without.
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on June 02, 2021, 10:53:43 am
Hi there I managed to get the dump file https://dffd.bay12games.com/file.php?id=15556 and I've uploaded it here.

One thing I have noticed and I don't know if it might cause some issues is the tilesets dont seem to be complete so things like workshops looking weird and the up down stairs being X when it should be a image would any issues with the tilesets potentially cause issues with the searching or are they completely separate?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 02, 2021, 11:51:45 am
Thanks. I'll see if I can get anything of of it (I think I've looked at a dump only once, and that wasn't on a PC).

I think it's unlikely the tile set should be the culprit, as the plugin doesn't use the tile set at all, but rather characters (which aren't tiles, at least not in the normal sense).

Edit: I can sort of open the dump file with Visual Studio, but it seems to demand a debug symbol file for SDLreal.dll in the form of an SDL.pdb file. I first tried the one generated when DFHack was compiled with debug symbols, but that file was rejected as it wasn't considered to match. I then tried to recompile DFHack in Release mode, but that didn't produce any debug symbol file (which isn't completely unexpected).
VS' Output also shows a lot of reports that DLLs were compiled without symbols.

However, the Call Stack tab shows an address in SDLreal.dll, with the rest of the call stack entries pointing to DF itself, and the fact that it refers to SDLreal.dll is odd, since that ought to be DF's original version of SDL.dll, rather than the DFHack one, as if DF was running with the original DLL but somehow managed to call DFHack ones anyway (I tried to start DF with DFHack disabled, and couldn't reach the Embark Assistant, as expected).

Thus, unless someone who actually knows how to examine a crash dump can get something out of it (e.g. by matching the assembly at the address against code generated with symbols), I suspect we need it captured with symbols.

This is the code at the last call stack location:

00007FFDC856E804  test        eax,eax 
00007FFDC856E806  je          00007FFDC856E82F 
00007FFDC856E808  cmp         eax,102h 
00007FFDC856E80D  je          00007FFDC856E824 
00007FFDC856E80F  lea         rcx,[7FFDC859A200h] 
00007FFDC856E816  call        00007FFDC856C2E0 
00007FFDC856E81B  or          eax,0FFFFFFFFh 
00007FFDC856E81E  add         rsp,20h 
00007FFDC856E822  pop         rbx 
00007FFDC856E823  ret 
00007FFDC856E824  mov         eax,1 
00007FFDC856E829  add         rsp,20h 
00007FFDC856E82D  pop         rbx 
00007FFDC856E82E  ret 
00007FFDC856E82F  lock dec    dword ptr [rbx+8] 
00007FFDC856E833  xor         eax,eax 
00007FFDC856E835  add         rsp,20h 
00007FFDC856E839  pop         rbx 
00007FFDC856E83A  ret 

This operation looks like it could point to an invalid location "00007FFDC856E82F  lock dec    dword ptr [rbx+8]" if rbx contained garbage.
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on June 02, 2021, 03:52:03 pm
However, the Call Stack tab shows an address in SDLreal.dll, with the rest of the call stack entries pointing to DF itself, and the fact that it refers to SDLreal.dll is odd, since that ought to be DF's original version of SDL.dll, rather than the DFHack one, as if DF was running with the original DLL but somehow managed to call DFHack ones anyway (I tried to start DF with DFHack disabled, and couldn't reach the Embark Assistant, as expected).

Could you post the call stack? I'm not really sure how to interpret this.

I'm assuming you are aware that SDL.dll is essentially the DFHack core on Windows, and that SDLreal.dll is just a renamed copy of DF's SDL.dll (so I wouldn't be surprised if it expects debug info to be in "SDL.pdb", since that is likely compiled into the DLL). To my knowledge, DF will call functions in SDL.dll for any SDL functions, and DFHack will forward most of those calls to SDLreal.dll untouched. I don't believe there is a mechanism for SDLreal.dll to call into DF directly - there is some SDL code that gets called before main(), but that should be compiled into the DF executable as part of SDLmain.lib.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 02, 2021, 04:30:35 pm
I suspect we need it captured with symbols.
I'll try and create a debug version (aka "RelWithDebInfo") of the master-branch and upload it.
It might be so slow though that the crash won't be provoked, the next step would be "ReleaseOptWithDebSymbs" which I cobbled together myself when I needed to debug something in the later search process.

00007FFDC856E82F  lock dec    dword ptr [rbx+8] 
This operation looks like it could point to an invalid location "00007FFDC856E82F  lock dec    dword ptr [rbx+8]" if rbx contained garbage.
Searching for "lock dec dword ptr" brings up hits for "semaphore", "Multiprocessor Protection" and "atomics" - this all to me points to code that handles multi-threading or thread-safety - which kind of makes sense for the real SDL code, as I think I recall that it is the only part of DF that is multi-threaded.
If SDL crashes after embark-assistant somehow corrupted the memory this might be tricky
Anyone knows of any compiler options that activate runtime memory checks that induce a crash exactly at that moment when some invalid operation happens?
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 02, 2021, 05:43:06 pm
I'll try and create a debug version (aka "RelWithDebInfo") of the master-branch and upload it.
=> here we go https://dffd.bay12games.com/file.php?id=15559
@Deuslink: Could you please replace "SDL.dll" and "hack/plugins/embark-assistant.plug.dll" in your LNP with the files in the zip and try to reproduce the crash?
Then upload the new dump again - thank you very much!
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 02, 2021, 05:52:17 pm
@lethosor: This is what the call stack looks like.

>   SDLreal.dll!00007ffdc856e804()   Unknown
    Dwarf Fortress.exe!00007ff775ad9a6d()   Unknown
    Dwarf Fortress.exe!00007ff775ada0a7()   Unknown
    Dwarf Fortress.exe!00007ff775ada580()   Unknown
    Dwarf Fortress.exe!00007ff775ada87d()   Unknown
    Dwarf Fortress.exe!00007ff775adb062()   Unknown
    Dwarf Fortress.exe!00007ff77645cf8e()   Unknown
    Dwarf Fortress.exe!00007ff77645cd25()   Unknown
    Dwarf Fortress.exe!00007ff77645c1fa()   Unknown
    [External Code]   

And, @Deuslink: I suggest renaming SDL.dll to e.g. SDL.dll.orig and embark-assistant.plug.dll to embark-assistant.plug.dll.orig rather than replacing them. This would allow you to easily restore your system to the original configuration. And thanks for your support so far!
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on June 02, 2021, 06:19:15 pm
Hi there Happy to help so I found and replaced them thanks for the advice about putting .orig after them. Just to confirm the only two files I  replaced are the SDL.dll and embark-assistant.plug.dll

I have done this and used a previous world and it crashed when I searched Good - Present
Dump file https://dffd.bay12games.com/file.php?id=15560

I created a new world just in case and it also froze (not responding) with the same filter
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on June 02, 2021, 11:43:50 pm
@lethosor: This is what the call stack looks like.

>   SDLreal.dll!00007ffdc856e804()   Unknown
    Dwarf Fortress.exe!00007ff775ad9a6d()   Unknown
    Dwarf Fortress.exe!00007ff775ada0a7()   Unknown
    Dwarf Fortress.exe!00007ff775ada580()   Unknown
    Dwarf Fortress.exe!00007ff775ada87d()   Unknown
    Dwarf Fortress.exe!00007ff775adb062()   Unknown
    Dwarf Fortress.exe!00007ff77645cf8e()   Unknown
    Dwarf Fortress.exe!00007ff77645cd25()   Unknown
    Dwarf Fortress.exe!00007ff77645c1fa()   Unknown
    [External Code]   

I suppose the answer to this question isn't really relevant, but I'd be interested in knowing whether ">" marks the current or oldest frame. If current, I would expect to see an intermediate call to SDL.dll, and I don't think such a call could have been optimized out. If oldest, it's possible that DF has registered a callback that SDL calls - this feels more feasible to me, since it wouldn't need to go through DFHack's SDL.dll, but I'm unaware of DF code that does this explicitly.

To RedDwarfStepper's points: DF does use some threading primitives implemented by SDL. Hard to say if that's part of this stack trace without knowing what "SDLreal.dll!00007ffdc856e804()" refers to, though. Multithreading isn't exclusive to the SDL layer, but that's what provides e.g. locks that DF uses.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 03, 2021, 02:37:57 am
I assume the stack trace has the most recent address at the top, but this is the first time I've looked at a Windows dump (I'm using Visual Studio), so I certainly can't claim to know.
However, to me it looks like Windows starts DF which then goes through a number of internal calls before ending up in SDLreal.dll (as noted, without any registered redirection via SDL.dll).

I'll grab Deuslinks' new dump to see if I can get anything useful out of that.

Edit:
This call stack looks a lot saner:
    SDLreal.dll!00007ffdcbcee804()   Unknown
>   SDL.dll!00007ffd42a1da19()   Unknown
    Dwarf Fortress.exe!00007ff775ad9a6d()   Unknown
    Dwarf Fortress.exe!00007ff775ada0a7()   Unknown
    Dwarf Fortress.exe!00007ff775ada580()   Unknown
    Dwarf Fortress.exe!00007ff775ada87d()   Unknown
    Dwarf Fortress.exe!00007ff775adb062()   Unknown
    Dwarf Fortress.exe!00007ff77645cf8e()   Unknown
    Dwarf Fortress.exe!00007ff77645cd25()   Unknown
    Dwarf Fortress.exe!00007ff77645c1fa()   Unknown
    [External Code]   

(The ">" is at SDL.dll because I've shifted the focus there: it was at the top originally).
The SDL.pdb file I've got still doesn't match.

However, I'm not sure if it's new data or just me noticing it, but EAX and EDX both are shown to have a value of 0 in SDLreal.dll. RBX = 1549282935824, corresponding to 168B8758410h, which doesn't seem to be an address anywhere near the other addresses used, which I suspect is the direct cause of the crash. However, I don't see where it got corrupted.

The code referenced in SDL.dll is
00007FFD42A1DA13  call        qword ptr [7FFD432CFE90h]  ; This is the instruction before the one referenced.
> 00007FFD42A1DA19  add         rsp,28h  ; This is the address referenced. Might it be the address the SDLreal.dll call should return to?
00007FFD42A1DA1D  ret
with RSP having a value of 0000000F104FF5F0h

The last (i.e. topmost) DF call stack entry refers to this:
00007FF775AD9A67  call        qword ptr [7FF7764B85C0h]  ; This is the instruction before the one referenced.
> 00007FF775AD9A6D  mov         rcx,qword ptr [rbx+100h]  ; This is the address referenced.
00007FF775AD9A74  call        qword ptr [7FF7764B85C0h] 
00007FF775AD9A7A  lea         rdx,[rsp+30h] 
00007FF775AD9A7F  mov         rcx,rdi 
00007FF775AD9A82  call        00007FF775ADC430 
00007FF775AD9A87  mov         rdx,rax 
00007FF775AD9A8A  mov         rax,qword ptr [rax] 
00007FF775AD9A8D  test        rax,rax 
00007FF775AD9A90  jne         00007FF775AD9A97 

Here RBX has a value of 00007FF777293C10h

(I've added ">" to the assembly snippets above to indicate the instructions indicated by VS, plus the comments after the instructions).

Edit 2:
Yes, the SDL.dll call instruction before the one in the call stack calls this (I've enabled display of data in addition to assembly to be able to decode the address from the referenced memory, which is why it looks messy, as columns aren't preserved):
> 00007FFDCBCEE7C0 83 CA FF             or          edx,0FFFFFFFFh 
00007FFDCBCEE7C3 E9 08 00 00 00       jmp         00007FFDCBCEE7D0 
00007FFDCBCEE7C8 CC                   int         3 
00007FFDCBCEE7C9 CC                   int         3 
00007FFDCBCEE7CA CC                   int         3 
00007FFDCBCEE7CB CC                   int         3 
00007FFDCBCEE7CC CC                   int         3 
00007FFDCBCEE7CD CC                   int         3 
00007FFDCBCEE7CE CC                   int         3 
00007FFDCBCEE7CF CC                   int         3 
2>00007FFDCBCEE7D0 40 53                push        rbx 
00007FFDCBCEE7D2 48 83 EC 20          sub         rsp,20h 
00007FFDCBCEE7D6 48 8B D9             mov         rbx,rcx 
00007FFDCBCEE7D9 48 85 C9             test        rcx,rcx 
00007FFDCBCEE7DC 75 15                jne         00007FFDCBCEE7F3 
00007FFDCBCEE7DE 48 8D 0D 03 BA 02 00 lea         rcx,[7FFDCBD1A1E8h] 
00007FFDCBCEE7E5 E8 F6 DA FF FF       call        00007FFDCBCEC2E0 
00007FFDCBCEE7EA 83 C8 FF             or          eax,0FFFFFFFFh 
00007FFDCBCEE7ED 48 83 C4 20          add         rsp,20h 
00007FFDCBCEE7F1 5B                   pop         rbx 
00007FFDCBCEE7F2 C3                   ret 
00007FFDCBCEE7F3 48 8B 09             mov         rcx,qword ptr [rcx] 
00007FFDCBCEE7F6 83 C8 FF             or          eax,0FFFFFFFFh 
00007FFDCBCEE7F9 3B D0                cmp         edx,eax 
00007FFDCBCEE7FB 0F 44 D0             cmove       edx,eax 
00007FFDCBCEE7FE FF 15 C4 99 02 00    call        qword ptr [7FFDCBD181C8h] 
The snippet above is the SDLreal.dll code immediately before the one recorded in the call stack, and "2>" is where the call should jump to. As far as I can see, RBX is pushed and the code then loads something else into it.
At the end there is the call to:
00007FFDE17D4AB0 FF 25 72 D7 05 00    jmp         qword ptr [7FFDE1832228h] 
with the data at that address, unfortunately, shown as 00 00 7F FD ?? ?? ?? 90, so I can't determine the destination of the jump.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 03, 2021, 07:45:04 am
I'll have to confess I'm really out of my depth here.
My initial hope was that using a debug-version of the plugin would provide more readable call stacks.
But seeing that the last call stack mostly happens in Dwarf Fortress.exe (for which we don't have any sources) itself and not in any code associated with DFhack this probably won't be the case.
Especially if it is really is corrupted memory, which like a booby trap only triggers after being set and left alone.

So I'd like to suggest an additional/alternative approach, one where I can actually contribute something apart from confusion:
- our current assumption is that the error has its cause in the embark-assistant plugin. As we have 1.5/2 data points and the CTD is very likely to happen when a search with embark-assistant is started I think this is a strong hypothesis.
- my/our (implicit) assumption is that it is caused by code that was added recently (version-wise) as we haven't had any such bug reports previously. Not as strong a hypothesis as the previous one but good enough to work with for the moment.
To prove or refute these assumptions we could create a version of the plugin that corresponds to version 0.47.05-beta1 or perhaps better 0.47.04-r5.
If the error is gone then we are sure that something added after that version is the cause - otherwise we have to go further back.
Rinse and repeat until the error is gone or until it gets very unlikely that embark-assistant is the sole cause.
Then we can slowly start readding isolated changes until we get the crash again... so some kind of binary search + divide and conquer on the source code level.
Any thoughts?

PS: I can probably get a first version done tonight if Deuslinks still is game.
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on June 03, 2021, 07:47:37 am
Im still game for helping and testing
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 03, 2021, 10:09:41 am
Well, RedDwarfStepper, you're not the only one whose feet don't reach the bottom...

The regression method seems to be our most likely avenue forwards (or is it backwards), although I don't have much hope. The Embark Assistant triggering the issue doesn't necessarily mean it actually caused it, but exploring what we can is better than giving up, and we still have a willing test subject.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 03, 2021, 05:44:14 pm
So - some family stuff came up and I really need to get some sleep now...
I hope I'll get a little free time during the day tomorrow to run the compiler with the reverted sources, otherwise I'll burn some midnight oil.
I'll create a zip that contains all the versions back to 0.47.04-r4 in the first go to make the testing easier.
And as a bonus I'll throw in a variant of the current version as I have an inkling of what might be the root of this, but as it might be completely bogus I won't spoil the surprise.
Only that much - @Deuslinks: How old is your CPU and would you say it is fast - say compared to one that is around 9 years old, like an Intel Core i5 3570 for example?
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on June 03, 2021, 06:11:46 pm
The cpu is very new had the whole pc built last month it is a AMD Ryzen 5 5600X Six Core CPU (3.7GHz-4.6GHz/35MB CACHE/AM4).


Also no.worries things going on in life take precedence.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 04, 2021, 04:16:03 pm
The cpu is very new had the whole pc built last month it is a AMD Ryzen 5 5600X Six Core CPU (3.7GHz-4.6GHz/35MB CACHE/AM4).
hehe, thought so - oh I really hope I'm right.

Also no.worries things going on in life take precedence.
Thanks for that. Also believe me I was beyond worrying at that moment more asleep than awake :D but giving a heads up so no one waits needlessly was the easy and right thing to do.

Ok, so here we go
https://dffd.bay12games.com/file.php?id=15562
The zip contains 5 adapted versions of the plugin (all build against dfhack 0.47.05-r1), starting with the current version without changes (0._0.47.05_r1_embark-assistant.plug.dll) just to make absolutely super sure it still causes a crash.
If it does not, well, I checked with the release on github (https://github.com/DFHack/dfhack/releases/download/0.47.05-r1/dfhack-0.47.05-r1-Windows-64bit.zip) and the two files are pretty different.... So I'm wondering - but lets not go there for now.
It also contains the unchanged original dll files from the respective release in the folder "_originals", they are there just for reference sake and can be ignored for now.

@Deuslinks: You can just copy the dlls into your plugins directory - you'll see a warning for each one but they won't interfere with the properly named "embark-assistant.plug.dll".
As per PatrikLundell's very good suggestion keep your original "embark-assistant.plug.dll" around by renaming it to "embark-assistant.plug.dll.orig".
Now starting with "0._0.47.05_r1_embark-assistant.plug.dll" create a copy of the file and rename the copy to "embark-assistant.plug.dll" - it might be easier to delete the current "embark-assistant.plug.dll" beforehand depending on your workflow/file handling tools.
Then do your thing :)
Rinse and repeat with the next version in increasing order if the currently tested crashes.
For the moment we're only interested in the version which reliably does not cause a crash. If even the last version ("4._0.47.04-r4_embark-assistant.plug.dll") causes a crash - well - let me know :)
Also let me know if there are any other questions.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 04, 2021, 05:37:31 pm
It can be useful to know that Windoze has some stupidity going on with locked files when DF crashes, i.e. it's possible you can't delete the DLLs after DF has crashed because Windoze somehow thinks the files are still in use. When that happens I rename them by adding the suffix ".junk" to them to remind me that I can remove the garbage after the computer has been restarted. After renaming the file(s) you can then then reuse the original name without problems.
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on June 12, 2021, 11:28:21 am
Hi there apologies for being missing the last week Work/Personal life + accidentally smashing my monitor really threw a spanner in all my plans. I have replaced the embark assistant dll file using each one and built new worlds and it still crashes

Ive uploaded dump files here it is odd as it will occasionally work Maybe once every 4 or so times but I cannot nail down a reason for it working even following the same steps on previous ones where it has worked
The pic ive uploaded is from the DFhack box and shows one working and the one after failing it just hangs on the [DFHACK#] where as the one that worked came up with the unit transparency message

Files for 0-2
https://dffd.bay12games.com/file.php?id=15571

Files for 3-4
https://dffd.bay12games.com/file.php?id=15569

Pic of DFhack box
https://dffd.bay12games.com/file.php?id=15570
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 13, 2021, 03:53:52 am
The "Unit transparency enabled" message seems to be generated by TwbT (doesn't appear when I use "STANDARD" as the print mode, but does show up with "TWBT". Unfortunately, it doesn't crash for me with TWBT either, so even if it would be the cause, it's not consistent.
However, I'd try to use a different print mode than TwbT to see if that works better, as TwbT is know to have bugs (such as frequently/usually crashing on embark).

I tried to look at the crash dumps and it looks like all of them crash along the same call chain (which I guess is good in that it seems to be the same one all the time), but I still don't get anything more out of it. I hope RedDwarfStepper might be able to use the symbol files produced when the DLLs were produced to make the dumps somewhat more intelligible, though.
Title: Re: DFHack plugin embark-assistant
Post by: Schmaven on June 13, 2021, 06:05:36 am
Not a major issue, but in my experience, searching for waterfalls only returns results if a previous search with some other parameter has been run.  Looking for a minimum drop of 5 gave 0 matching world tiles.  Running the search again for a minimum river of brook yielded nearly the entire map.  Then running it again with just a waterfall drop of 5 produced 459 results.  Running 2 searches is still waaaaaaaay faster than just looking at random river junctions with the relative elevation view, so thank you for the work involved in making this possible :)

Edit: I just tried another search on the same world, this time with other parameters together with the waterfall min=5 and it came back with 0.  So I ran it again, same criteria, butfor waterfall min=NA and it found many results.  Ran again, the same butfor waterfall min=5 and it came up with a bunch.  So it seems to consistently require the first search to not include waterfalls.  IIRC, it was mentioned somewhere in the thread about how the search looks at rivers and elevations to determine waterfall heights, so I think it just might require 2 searches to do that.  I suppose I was just thinking that if there was some simple way to run the preliminary search "behind the scenes" it would seem like just the first search found them.  There were a number of embarks I've done in the past where I never searched for waterfalls the 2nd time, just assuming my world had none, but that's on me for not being persistent. 
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 13, 2021, 07:45:02 am
@Schmaven: Your description indicates there's a bug somewhere (I haven't yet looked into it) that dismisses waterfalls prematurely for the first search, for some reason. The second and subsequent searches should all give the same result (with the same parameters, of course), or there's a bug in that logic.

The reason the first search isn't run "behind the scene" is that it takes such a long time in a full sized world.
Title: Re: DFHack plugin embark-assistant
Post by: Schmaven on June 13, 2021, 08:26:36 am
After the first search, all subsequent searches are accurate and consistent from what I've seen, so to clarify, the false negative only manifests on the very first search.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 13, 2021, 10:52:50 am
@Schmaven: I've found the bug (the code attempted to compare the maximum waterfall size in the world tiles before this info had been collected, and thus rejected all tiles.

The fixed code (when accepted and then included in a new DFHack release) will still suffer from the general problem with the first search, i.e. it won't pick up matches at the edges of the embark area (because that requires mutual access to the info in neighboring world tiles, which means they can't be searched reliably until the second attempt).
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 15, 2021, 03:30:19 pm
I tried to look at the crash dumps and it looks like all of them crash along the same call chain (which I guess is good in that it seems to be the same one all the time), but I still don't get anything more out of it. I hope RedDwarfStepper might be able to use the symbol files produced when the DLLs were produced to make the dumps somewhat more intelligible, though.

I really thought and kind of hope-feared that one of my last changes broke it. Some missing or half-faulty initialization. So I created release dlls for the tests of Deuslinks ...
But as PatrikLundell said that the call chain is unchanged I'll have a look at the crash log of the debug dll we tested at the beginning of June - for that I still have the original symbol files - just made a backup of those to be sure.
I'll try to find time for it at the weekend - my high functioning free time is currently quite limited - and I don't want to mess this up with a sleepy brain.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 19, 2021, 10:52:39 am
The main thread is a follows:
Code: [Select]
ntdll.dll!NtWaitForSingleObject() Unknown
  KERNELBASE.dll!WaitForSingleObjectEx() Unknown
  SDLreal.dll!00007ffdcbcee804() Unknown
> SDL.dll!SDL_SemWait(void * sem) Line 707 C++
  Dwarf Fortress.exe!00007ff775ad9a6d() Unknown
  Dwarf Fortress.exe!00007ff775ada0a7() Unknown
  Dwarf Fortress.exe!00007ff775ada580() Unknown
  Dwarf Fortress.exe!00007ff775ada87d() Unknown
  Dwarf Fortress.exe!00007ff775adb062() Unknown
  Dwarf Fortress.exe!00007ff77645cf8e() Unknown
  Dwarf Fortress.exe!00007ff77645cd25() Unknown
  Dwarf Fortress.exe!00007ff77645c1fa() Unknown
  kernel32.dll!BaseThreadInitThunk() Unknown
  ntdll.dll!RtlUserThreadStart() Unknown

the worker thread concerning embark-assistant:
Code: [Select]
> embark-assistant.plug.dll!std::distance<std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<enum df::enums::interface_key::interface_key> > > >(std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<enum df::enums::interface_key::interface_key> > > _First, std::_Tree_const_iterator<std::_Tree_val<std::_Tree_simple_types<enum df::enums::interface_key::interface_key> > > _Last) Line 1126 C++
  embark-assistant.plug.dll!embark_assist::overlay::ViewscreenOverlay::interpose_fn_feed(std::set<enum df::enums::interface_key::interface_key,std::less<enum df::enums::interface_key::interface_key>,std::allocator<enum df::enums::interface_key::interface_key> > * input) Line 104 C++
  SDL.dll!df::viewscreen::feed_key(df::enums::interface_key::interface_key key) Line 5 C++
  embark-assistant.plug.dll!embark_assist::matcher::find(embark_assist::defs::match_iterators * iterator, std::vector<embark_assist::defs::geo_datum,std::allocator<embark_assist::defs::geo_datum> > * geo_summary, std::vector<std::vector<embark_assist::defs::region_tile_datum,std::allocator<embark_assist::defs::region_tile_datum> >,std::allocator<std::vector<embark_assist::defs::region_tile_datum,std::allocator<embark_assist::defs::region_tile_datum> > > > * survey_results, std::vector<std::vector<embark_assist::defs::matches,std::allocator<embark_assist::defs::matches> >,std::allocator<std::vector<embark_assist::defs::matches,std::allocator<embark_assist::defs::matches> > > > * match_results) Line 2967 C++
  embark-assistant.plug.dll!embark_assist::main::match() Line 90 C++
  embark-assistant.plug.dll!embark_assist::overlay::ViewscreenOverlay::interpose_fn_render() Line 244 C++
  Dwarf Fortress.exe!00007ff775d4fef8() Unknown
  Dwarf Fortress.exe!00007ff775ad9e22() Unknown
  Dwarf Fortress.exe!00007ff775adadd9() Unknown
  SDLreal.dll!00007ffdcbcee471() Unknown
  SDLreal.dll!00007ffdcbcee855() Unknown
  ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void *),1>() Unknown
  kernel32.dll!BaseThreadInitThunk() Unknown
  ntdll.dll!RtlUserThreadStart() Unknown

Really can't say anything concerning the main thread, apart from
Code: [Select]
ntdll.dll!NtWaitForSingleObject()does not sound so bad/crashy.
But the ea worker thread, hm, the last real source code line 104 corresponds to this
Code: [Select]
input->count(df::interface_key::SETUP_LOCAL_Y_UP) ||https://github.com/DFHack/dfhack/blob/2fc5fbacb5bdf7183d61045a4786d58571081eec/plugins/embark-assistant/overlay.cpp#L104
and ends up in xutility:
Code: [Select]
template<class _InIt> inline
_Iter_diff_t<_InIt>
distance(_InIt _First, _InIt _Last)
{ // return distance between iterators
return (_Distance1(_First, _Last, _Iter_cat_t<_InIt>()));
}
via in xtree
Code: [Select]
size_type count(const key_type& _Keyval) const
{ // count all elements that match _Keyval
_Paircc _Ans = equal_range(_Keyval);
return (_STD distance(_Ans.first, _Ans.second));
}

Could it be that input gets messed up/invalid? Or that DEFINE_VMETHOD_INTERPOSE misbehaves? Also there is a reference to
Code: [Select]
SDL.dll!DFHack::Core::getHotkeyCmdin another worker thread (see below) those two might interact in a bad way - just throwing out wild theories ...


There are 3 more worker threads that contains references to dfhack
1.:
Code: [Select]
ntdll.dll!NtWaitForSingleObject() Unknown
  mswsock.dll!SockWaitForSingleObject() Unknown
  mswsock.dll!WSPAccept() Unknown
  ws2_32.dll!WSAAccept() Unknown
  ws2_32.dll!accept() Unknown
> SDL.dll!CPassiveSocket::Accept() Line 244 C++
  SDL.dll!`anonymous namespace'::ServerMainImpl::threadFn(std::promise<bool> promise, int port) Line 475 C++
  SDL.dll!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int>,std::default_delete<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int> > > >::_Execute<0,1,2>(std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int> & _Tup, std::integer_sequence<unsigned __int64,0,1,2> __formal) Line 241 C++
  SDL.dll!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int>,std::default_delete<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int> > > >::_Run(std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int>,std::default_delete<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int> > > > * _Ln) Line 247 C++
  SDL.dll!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int>,std::default_delete<std::tuple<void (__cdecl*)(std::promise<bool>,int),std::promise<bool>,int> > > >::_Go() Line 233 C++
  SDL.dll!std::_Pad::_Call_func(void * _Data) Line 210 C++
  ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void *),1>() Unknown
  kernel32.dll!BaseThreadInitThunk() Unknown
  ntdll.dll!RtlUserThreadStart() Unknown
2.:
Code: [Select]
ntdll.dll!NtDeviceIoControlFile() Unknown
  KERNELBASE.dll!ConsoleCallServerGeneric() Unknown
  KERNELBASE.dll!GetConsoleInput() Unknown
  KERNELBASE.dll!ReadConsoleInputA() Unknown
> SDL.dll!DFHack::Private::prompt_loop(tthread::recursive_mutex * lock, DFHack::CommandHistory & history) Line 288 C++
  SDL.dll!DFHack::Private::lineedit(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & prompt, std::basic_string<char,std::char_traits<char>,std::allocator<char> > & output, tthread::recursive_mutex * lock, DFHack::CommandHistory & ch) Line 386 C++
  SDL.dll!DFHack::Console::lineedit(const std::basic_string<char,std::char_traits<char>,std::allocator<char> > & prompt, std::basic_string<char,std::char_traits<char>,std::allocator<char> > & output, DFHack::CommandHistory & ch) Line 598 C++
  SDL.dll!fIOthread(void * iodata) Line 1494 C++
  SDL.dll!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64>,std::default_delete<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64> > > >::_Run(std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void *),void *>,std::default_delete<std::tuple<void (__cdecl*)(void *),void *> > > > * _Ln) Line 247 C++
  SDL.dll!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64>,std::default_delete<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64> > > >::_Go() Line 233 C++
  SDL.dll!std::_Pad::_Call_func(void * _Data) Line 210 C++
  ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void *),1>() Unknown
  kernel32.dll!BaseThreadInitThunk() Unknown
  ntdll.dll!RtlUserThreadStart() Unknown
3.:
Code: [Select]
ntdll.dll!NtWaitForAlertByThreadId() Unknown
  ntdll.dll!RtlSleepConditionVariableSRW() Unknown
  KERNELBASE.dll!SleepConditionVariableSRW() Unknown
  [Inline Frame] msvcp140.dll!Concurrency::details::stl_condition_variable_win7::wait_for(Concurrency::details::stl_critical_section_interface *) Line 216 C++
  msvcp140.dll!Concurrency::details::stl_condition_variable_win7::wait(Concurrency::details::stl_critical_section_interface * lock) Line 210 C++
> msvcp140.dll!do_wait(_Cnd_internal_imp_t * cond, _Mtx_internal_imp_t * mtx, const xtime * target) Line 77 C++
  SDL.dll!std::condition_variable::wait(std::unique_lock<std::mutex> & _Lck) Line 565 C++
  SDL.dll!DFHack::Core::getHotkeyCmd(bool & keep_going) Line 1913 C++
  SDL.dll!fHKthread(void * iodata) Line 234 C++
  SDL.dll!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64>,std::default_delete<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64> > > >::_Run(std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void *),void *>,std::default_delete<std::tuple<void (__cdecl*)(void *),void *> > > > * _Ln) Line 247 C++
  SDL.dll!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64>,std::default_delete<std::tuple<void (__cdecl*)(void * __ptr64),void * __ptr64> > > >::_Go() Line 233 C++
  SDL.dll!std::_Pad::_Call_func(void * _Data) Line 210 C++
  ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void *),1>() Unknown
  kernel32.dll!BaseThreadInitThunk() Unknown
  ntdll.dll!RtlUserThreadStart() Unknown
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 19, 2021, 12:58:41 pm
Thanks for that. Unfortunately, I fail to any immediate culprit.

- I agree the main thread seems to just be waiting, which is reasonable and does seem to be harmless.
- The thread involving the Embark Assistant seems to be reacting to the survey as it moves the cursor around to, well, survey things, and this involves the display of the current status of the search.
- The first worker thread just seems to be waiting.
- The second worker thread seems to be the DFHack console waiting for things to happen.
- My guess about the third worker thread is that it is DFHack monitoring DF for keys to intercept (such as modifying advanced critera, e.g. sand display), but that's definitely just a guess.

So the EA thread feeds a key (presumably CURSOR_UP, although my local code apparently doesn't match the one examined), which is then intercepted and processed until line 104, where the input->count() operations tries to find whether the appropriate field in the set is set, but somehow blows up, despite the code having checked SETUP_LOCAL_X_DOWN on the previous line, and that enum value is 3 higher (assuming the set allocates values in numerical order, rather than according to some hash key). I have no idea how sets are implemented, but it doesn't make sense that checking a set should be capable of blowing up if you're actually using the correct set.
It can be noted that the key fed is the "raw" keyboard key, while the key checked against is the evaluated context matched one, but both keys belong to the same enum, and so should be within the same set. Also note that the key fed in is a single key, while the interpose code processes a set that DF has generated by processing the "keyboard" input character.

I can't say this feels like much progress...
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 19, 2021, 02:27:21 pm
Thanks for that. Unfortunately, I fail to any immediate culprit.
You're welcome. And: Yeah, me neither.

I have no idea how sets are implemented, but it doesn't make sense that checking a set should be capable of blowing up if you're actually using the correct set.
Well, if there is concurrent access to the set and at least one thread modifies the set while another thread reads it (=> count) this can lead to an inconsistent state that leads to undefined behaviour which can result in a crash.
The previous successful call to input->count() in the line above does not rule out this cause.
As Deuslinks reports the crash only happens most of the time, but not always - so race conditions and similar beasts and sadly memory access/allocation issues still are very much a possible reason.
Also that this - at least for Deuslinks - happens with a new and very fast CPU could point in that direction.

Just throwing some ideas out there:
- Are there any other plugins that are similar in their structure/design so that they could suffer from the same problem?
- Is there any language construct that we could use to isolate this specific location in the code just to make sure it's not the std::set? try-catch comes to mind - but I never have used it in C++ so I'm not sure.
- Can we make the system or the dlls we control report a proper error, like "access violation"? Or would this happen anyway and what we see is undefined behavior for sure?
- Would more crash dumps with the debug-dlls help? Perhaps we're missing something?
- @PatrikLundell: How old is your PC by the way? Perhaps - between the two of us - one has to buy/build a PC with current hardware - mine is - apart from the graphics card - 9 years old....

PS:
I can't say this feels like much progress...
Well with results of the modified dlls we learned that it is no recent change that causes the problem.
Also we know that it sometimes does work all the way through, which might point to some problem during initialization or the first iterations.

PPS:
One more thing I just found: The current pressed key is CURSOR_UPLEFT_FAST, coming from here
https://github.com/DFHack/dfhack/blob/1c32783dd2628f22c5355b84e49e5c7357b52cb8/plugins/embark-assistant/matcher.cpp#L2966
or to be exact here
https://github.com/DFHack/dfhack/blob/1c32783dd2628f22c5355b84e49e5c7357b52cb8/plugins/embark-assistant/matcher.cpp#L2967
so the end of a loop - hm.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 19, 2021, 03:31:54 pm
Concurrent access is always dangerous, of course, but I have trouble seeing this being the case with this set unless something is modifying dangling pointers, which I think ought to result in less consistent crashes. The set ought to be populated by DF and then only consumed downstream, even if that happens to be in multiple threads (and I don't think that's happening).

Improper cache management can lead to issues where different threads won't get access to "the same" data, but I don't know how C(++) handles that, although my single change to "code" written in Java involved changing a variable to make it available to multiple threads (the weird default in this padded cell scripting language is to cut babies to pieces by razor sharp optimization corners in that department).

I've never dealt with exceptions in C(++) either, although I've got plenty of experience with it from a high level language (and thus those programs almost never crashed in the C fashion, but with error logs about unhandled exceptions, allowing us to at least know where to start looking).

It looked like the code blew up in std::distance rather than in our code, so instrumenting that code would presumably require replacing it with an instrumented version. I don't know if try/catch would work, although it might, in which case I'd expect it to be possible to provide some output of whatever data we can think of (while trying to avoid poking it where it blows up again).

I don't think more of dump of the same code would help, but rather outputs from instrumented code that either tries to catch the exception and output info about the state and/or output corresponding data at each visit to the code (it should be a little over once per world tile when it doesn't crash, but probably the first or one of the first times when it does. It seemed to be an UP movement, though, not a MUP, so it's a single step rather than a 10 tile step).

I think I bought my current computer a little less than 1½ years ago, and it's a fairly high end one (AMD Ryzen 9 3950X).

It's true we've learned a bit about what the problem isn't caused by.
I don't see much that can race in this scenario. You've got DF's main thread that's basically waiting for input (and hands it over to other threads), the DF display thread that just run in a cycle where the writing to the memory it uses has to be synchronized with it (doing it from the wrong parts of the script in Lua illustrates what can happen if you do it incorrectly). You've got the EA main thread that essentially takes the role of DF's main thread.
Assuming the program blows up in the EA thread (do we know it's there, rather than the thread being at that location when things blow up elsewhere?) it looks like the data received is somehow corrupt, which is uncomfortable as it's provided by DF rather than our code (I'd rather get egg on my face from screwing up than being able to say it wasn't my fault when the former means I can actually fix it, but the latter doesn't).

Edit:
I hooked up the debugger and looked at the key codes sent to the interpose code, and it turned out to be the keys the "keyboard" sent most of the time. The exception was when changing from one block of world tiles to the next one, in which case the "keyboard" key input was followed by a SETUP_LOCAL_Y_MUP followed by a set consisting of both a SETUP_LOCAL_Y_MUP and a SETUP_LOCAL_Y_MDOWN (in a 17*17 world). It doesn't really matter which of these codes you get, though, as they only serve to trigger updates of the overlay (although this indicates we have a superfluous update at every transition).

Edit 2: I just saw the PPS:
That's indeed during the initiation phase where the focus is moved to the first world tile. It can be noted that it's somewhat "lazy" in that it just keeps moving the cursor until it hits the corner, ignoring whether you're "overshooting" or not, as DF cuts it back to the world boundaries (which it has to do when dealing with players).
The end of the loop is likely just the address the call should return to, which is to be expected based on what I saw from the assembly: the addresses pointed to were the ones following calls, rather than the addresses from which the calls were made.
And I see exactly the same call sequence when I use a debugger for the first CURSOR_UPLEFT_FAST key (and, I assume, the following ones). I get a set of size one with that key as its single element.
Title: Re: DFHack plugin embark-assistant
Post by: RedDwarfStepper on June 20, 2021, 05:26:54 pm
Assuming the program blows up in the EA thread (do we know it's there, rather than the thread being at that location when things blow up elsewhere?) it looks like the data received is somehow corrupt, which is uncomfortable as it's provided by DF rather than our code (I'd rather get egg on my face from screwing up than being able to say it wasn't my fault when the former means I can actually fix it, but the latter doesn't).
Thinking about it again, we really can't be sure that this is exactly what blows up. We only know for sure that EA is at least one part of the problem: If our user starts a search with EA it crashes. But that does not mean that no other plugin is contributing to this crash. It could very well be a combined effort of two or more actors... :)
So to make sure about that I have one more test for Deuslinks: remove all other plugins and try to provoke the crash.
Since that is a quite tedious test I'd like him to test something else before that. Another hunch...

@Deuslinks:
Could you please start a new session like always, best with a big world, load EA if not already done and manually move the cursor to the top left corner of the region view and only then open the view for the search criteria via 'f', change the criteria and then 'f' again?
Does it still crash right away? If so could you please upload the resulting DMP-file?
If is crashes but at the end of the search - so after some time instead of right away - please upload the resulting DMP-files and have a try with dll uploaded here (https://dffd.bay12games.com/file.php?id=15577).
How does that one behave? If it crashes as well:
We (read: you) need to temporarily "deactivate" all other plugins that might interfere - this is more involved than the other tests, if you feel up to it you should have some time at your hands and best create a copy of your LNP/PeridexisErrant's Starter Pack so you don't destroy your regular setup.
Okay, here we go:
- Please move all plugin-dlls with the exception of embark-assistant.plug.dll from the plugins folder to a separate folder, e.g. "deactivated_plugins" or just create a copy of the "Dwarf Fortress 0.47.05\hack\plugins\" folder, rename the copy to "deactivated_plugins" and then remove the dlls from the original folder
- The only remaining dll-file in the plugins folder should be the "embark-assistant.plug.dll" with a size of around 653 KB, that you downloaded from here (https://dffd.bay12games.com/file.php?id=15559).
Do what you do and never mind the warning about the missing plugins... Crash? => Please upload the dump and don't mind my sobbing ;D
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on June 20, 2021, 10:15:50 pm
- Would more crash dumps with the debug-dlls help? Perhaps we're missing something?
In general, I would say yes. You currently have a crash dump with several active threads, and it can be difficult to know where the crash actually originated sometimes, despite what the dump might say. It's likely that the crash occurred in the embark-assistant thread, given that using embark-assistant triggers the crash, but it would be easier to rule out unrelated threads with a handful of other crash dumps (say, 5 maybe).

Your advice about disabling other plugins is also a good idea.

Quote
PPS:
One more thing I just found: The current pressed key is CURSOR_UPLEFT_FAST, coming from here
https://github.com/DFHack/dfhack/blob/1c32783dd2628f22c5355b84e49e5c7357b52cb8/plugins/embark-assistant/matcher.cpp#L2966
or to be exact here
https://github.com/DFHack/dfhack/blob/1c32783dd2628f22c5355b84e49e5c7357b52cb8/plugins/embark-assistant/matcher.cpp#L2967
so the end of a loop - hm.

One possible important thing to check would be to ensure that the core is suspended when matcher.cpp calls feed_key() - this is writing data that DF reads from, so if DF is accessing that data at the same time, there could be a possible race condition there. I'm not sure why that would result in a crash when reading from a std::set, though - that should be local to the calling thread.

Edit: per "Core::getInstance().isSuspended()" it does appear to be suspended here (https://github.com/DFHack/dfhack/blob/1c32783dd2628f22c5355b84e49e5c7357b52cb8/plugins/embark-assistant/matcher.cpp#L2966), which is good.

Edit: one more thing: the getHotkeyCmd() thread is normal and expected to be idle in that function. It typically acts only on DFHack-managed hotkeys (registered with the "keybinding" command). feed_key() probably can't trigger this thread.
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on June 21, 2021, 01:30:18 am
Thanks for chiming in lethosor, I think we need all the help we can get.

I agree disabling as much unrelated functionality as possible is a good approach, and testing to see what happens if we start in the top left corner is good as well (if it doesn't crash, repeat a couple of times to ensure it's not one of the fluke successful runs).

When I put a breakpoint at the indicated location in EA on my machine, I did get one call that was initiated by embark-tools (I think the key issued was A102, but I may be misremembering). As far as I could tell that happened after the first feature shell had been processed, which is the time at which the UI replaced the find profile overlay with the search result one (which also displays the native DF UI "underneath", and thus the embark-tools additional UI as well). However, this happens after the point we believe we see the crash happening at.
Title: Re: DFHack plugin embark-assistant
Post by: Deuslinks on June 22, 2021, 04:10:13 am
Hi there I will give it a shot tonight and report the results for you.
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on June 23, 2021, 11:09:24 pm
I did get one call that was initiated by embark-tools (I think the key issued was A102, but I may be misremembering)
For what it's worth, this is normal when other plugins are enabled and hook into the same screen - they'll end up calling each others' hooks, and unless they specify a priority, there's not a fixed order to these calls across DF runs (although they should usually occur in the same order in a single DF session, unless plugins are loaded/unloaded).
Title: Re: DFHack plugin embark-assistant
Post by: snowyscales on December 14, 2021, 02:12:19 pm
(https://i.imgur.com/jb3M5Vi.png)

so i noticed these bright red abreviations that sometimes show below the sand/clay/soil list. and i can figure the "Re" mean Reanimating and the "Th" means Thralling. but what does the "TS" mean and what other abbreviations(and their meanings) can be shown in that section?
Title: Re: DFHack plugin embark-assistant
Post by: lethosor on December 14, 2021, 08:48:34 pm
There's a description of them in the embark-assistant help in-game - looks like on the screen titled "Embark Assistant Help/Info General Page".

Quote
Evil weather, when present: BR = Blood Rain, TS = Temporary Syndrome
PS = Permanent Syndrome, Re = Reanimating, and Th = Thralling. Incursions.
Title: Re: DFHack plugin embark-assistant
Post by: A_Curious_Cat on October 22, 2023, 02:10:17 am
Any chance that this will be updated for 50.X?
Title: Re: DFHack plugin embark-assistant
Post by: PatrikLundell on October 22, 2023, 02:28:07 am
I will investigate if I'm able to do so only when DF becomes playable, i.e. keyboard support is returned. That doesn't stop mouse tolerant people to take up the task earlier, as this is part of DFHack.

I can mention two things here:
- The biome determination logic was changed prior to the Premium release, so some biome determinations were incorrect. The underlying logic could use an update, although it's no longer part of this plugin itself. The differences were not huge, but present.
- I've noticed that mousing around pre embark causes mid level tiles to get loaded, so once you can order the cursor to move with keyboard input again you should be able to load all of this info into memory before performing any processing, thus removing issues with having to cache information and processing the data in two passes. It can be noted that the information is loaded unordered, but that can be handled e.g. with an intermediate coordinate translation matrix.