Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 197 198 [199] 200 201 ... 243

Author Topic: DFHack 50.13-r2  (Read 820264 times)

chickrickepachimecho

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2970 on: July 07, 2021, 09:05:05 pm »

Is there a way to use this struct

Code: [Select]
  struct DFHACK_EXPORT plant_tree_info {
    df::plant_tree_tile** body; /*!< dimension body_height */
    int16_t* extent_east; /*!< dimension body_height */
    int16_t* extent_south; /*!< dimension body_height */
    int16_t* extent_west; /*!< dimension body_height */
    int16_t* extent_north; /*!< dimension body_height */
    int32_t body_height;
    int32_t dim_x;
    int32_t dim_y;
    df::plant_tree_tile** roots; /*!< dimension roots_depth */
    int32_t roots_depth;
    int16_t unk6;
    static struct_identity _identity;
  public:
    plant_tree_info();
  };
to find the number of logs that the tree will produce?
Logged

myk

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2971 on: July 07, 2021, 09:27:56 pm »

If you are writing code to programmatically chop down trees then I am intrigued and would like to subscribe to your newsletter. This is the last bit of missing functionality from my dig-now plugin.
Logged

PatrikLundell

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2972 on: July 08, 2021, 02:02:42 am »

@chickrickepachimecho: Probably, as all the info is in there, although I don't know if anyone has researched how to calculate it.

My first attempt would be to simply walk through the tiles of the tree and count the number of trunks, cut down the tree, and compare the number to the number of logs found (obviously the area should either be free of other logs, or the preexisting logs should be marked with e.g. the 'f'orbidden flag to distinguish the new logs from the old ones).

I'd examine blood thorn (very high yield) as well as two and three tile diameter trees (I think highwood is the only one to produce 3 tile one, with some "normal" tree(s) being capable of producing 2 tile diameter trunks).

Also note that the "body" field has an odd description, saying "dimension body_height", while also describing the matrix as "dimension dim_x*dim_y" (the latter isn't shown in the C struct, but it's in the XML source for the C struct). This leads to the suspicion that it's actually a 3 dimensional array (body_height*dim_x*dim_y), which is what would be required to actually contain the info for all of the relevant tiles. However, be prepared for DF crashing if you try to access the structure that way, as it may well refer to unallocated memory if it's only a two dimensional structure. I'd also try to see if the bit combinations aren't nonsensical, as you shouldn't have "blocked" set together with anything else, and "trunk", "branches", and "twigs" probably should be mutually exclusive).

Edit: I've looked at my woodcutter cutting trees and counted the number of trunk segments present before cutting (using the Mk I eyeball) against the number of logs produced, and they've matched so far (surface trees, producing 2-7 logs). I don't have any wide trunk trees.
« Last Edit: July 08, 2021, 08:47:30 am by PatrikLundell »
Logged

stroppycarpet

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2973 on: July 08, 2021, 06:16:26 am »

If Dwarf Therapist is doing it correctly, there is no individual skill rate, it's only in castes (caste_raw.skill_rates). Did you try fixing the raws first? It might not need to re-run worldgen.

Unfortunately editing the raws contained in the save folder of my world does not fix it. At least, it doesn't fix it in my already-running fortress game. if I were to abandon and reclaim my fortress it might work, but I can't be bothered to do it.

I've noticed that since the rate is effectively -1%, my military commander that has this special caste (race: human, caste: Squire, female; in the masterwork mod, most recent download) she loses discipline over time when training in barracks if you hack her to have a score of .e.g. 7 in dfhack with assign-skills. So every now and then I need to check up on her and discipline her (literally).

For now I'll live with the minor invonvenience of having to give her discipline once every 2 years and keep soldiering on.

At least until I figure out the method or function to edit caste skill rates.
Logged

chickrickepachimecho

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2974 on: July 08, 2021, 12:46:13 pm »

How do you go about debugging a plugin that crashes? So far, I've been commenting code out, but I would like a faster way.
Logged

chickrickepachimecho

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2975 on: July 08, 2021, 01:49:22 pm »

@chickrickepachimecho: Probably, as all the info is in there, although I don't know if anyone has researched how to calculate it.

My first attempt would be to simply walk through the tiles of the tree and count the number of trunks, cut down the tree, and compare the number to the number of logs found (obviously the area should either be free of other logs, or the preexisting logs should be marked with e.g. the 'f'orbidden flag to distinguish the new logs from the old ones).

I'd examine blood thorn (very high yield) as well as two and three tile diameter trees (I think highwood is the only one to produce 3 tile one, with some "normal" tree(s) being capable of producing 2 tile diameter trunks).

Also note that the "body" field has an odd description, saying "dimension body_height", while also describing the matrix as "dimension dim_x*dim_y" (the latter isn't shown in the C struct, but it's in the XML source for the C struct). This leads to the suspicion that it's actually a 3 dimensional array (body_height*dim_x*dim_y), which is what would be required to actually contain the info for all of the relevant tiles. However, be prepared for DF crashing if you try to access the structure that way, as it may well refer to unallocated memory if it's only a two dimensional structure. I'd also try to see if the bit combinations aren't nonsensical, as you shouldn't have "blocked" set together with anything else, and "trunk", "branches", and "twigs" probably should be mutually exclusive).

Edit: I've looked at my woodcutter cutting trees and counted the number of trunk segments present before cutting (using the Mk I eyeball) against the number of logs produced, and they've matched so far (surface trees, producing 2-7 logs). I don't have any wide trunk trees.

So yea, the following code does indeed crash the game.
Code: [Select]
                    for (int i = 0; i < plant->tree_info->dim_x; i++) {
                        tilesRow = tiles[i];
                        for (int j = 0; j < plant->tree_info->dim_y; j++) {
                            trunks += tilesRow[j].bits.trunk;
                        }
                    }

Edit: Of course it does... should have looked like this
Code: [Select]
                    for (int i = 0; i < plant->tree_info->body_height; i++) {
                        tilesRow = tiles[i];
                        for (int j = 0; j < plant->tree_info->dim_y*plant->tree_info->dim_x; j++) {
                            trunks += tilesRow[j].bits.trunk;
                        }
                    }

The above code runs fine now.
« Last Edit: July 08, 2021, 02:03:08 pm by chickrickepachimecho »
Logged

chickrickepachimecho

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2976 on: July 08, 2021, 02:49:17 pm »

Can anyone tell me why the print statements are not working? I know the code is being run because feeding a null pointer to markPlant(tallestTree); causes the program to crash.

Code: [Select]
#include "Core.h"
#include "Console.h"
#include "Export.h"
#include "PluginManager.h"
#include "DataDefs.h"

#include "df/map_block.h"
#include "df/material.h"
#include "df/tiletype_material.h"
#include "df/plant.h"
#include "df/plant_raw.h"
#include "df/plant_tree_info.h"
#include "df/plant_tree_tile.h"
#include "df/world.h"

#include "modules/Designations.h"
#include "modules/Maps.h"
#include "modules/World.h"

#include <algorithm>
#include <sstream>
#include <string>

using namespace DFHack;
using namespace df::enums;

#define PLUGIN_VERSION 0.1
DFHACK_PLUGIN("talltree");
REQUIRE_GLOBAL(world);

static void markPlant(df::plant* plant);

static void markPlant(df::plant* plant) {
    if (Designations::canMarkPlant(plant)) {
        Designations::markPlant(plant);
    }
}

command_result talltree(color_ostream &out, std::vector<std::string> & params);

command_result talltree(color_ostream &out, std::vector<std::string> & params) {
    // Suspend the core before changing internal data
    CoreSuspender suspend;
    out.print("Valid?");
    if (Maps::IsValid()) {
        const df::plant_raw *plantRaw;
        bool chop = true;
        int maxLogs = 0;
        df::plant* tallestTree = 0;
        std::vector<df::plant*> doneGrowing{};
        for (auto & plant : world->plants.all) {
            int x = plant->pos.x % 16;
            int y = plant->pos.y % 16;
            df::map_block* tileBlock = Maps::getTileBlock(plant->pos);
            if (plant->flags.bits.is_shrub ||
                (plant->material != df::tiletype_material::TREE) ||
                !tileBlock ||
                tileBlock->designation[x][y].bits.hidden) {
                chop = false;
            }
            else {
                plantRaw = df::plant_raw::find(plant->material);
                if (plantRaw->material_defs.type[plant_material_def::drink]) {
                    chop = false;
                }
                for (auto material : plantRaw->material) {
                    if (material->flags.is_set(material_flags::EDIBLE_RAW) ||
                        material->flags.is_set(material_flags::EDIBLE_COOKED)) {
                        chop = false;
                    }
                }
                std::stringstream ss1;
                ss1 << "Chop: " << chop;
                out.print(ss1.str().c_str());
                if (chop) {
                    df::plant_tree_tile** tiles = plant->tree_info->body;
                    df::plant_tree_tile* tilesRow;
                    int trunks = 0;

                    for (int i = 0; i < plant->tree_info->body_height; i++) {
                        tilesRow = tiles[i];
                        for (int j = 0; j < plant->tree_info->dim_y*plant->tree_info->dim_x; j++) {
                            trunks += tilesRow[j].bits.trunk;
                        }
                    }
                    std::stringstream ss;
                    ss << "Trunks: " << trunks;
                    out.print(ss.str().c_str());
                    maxLogs = std::max(maxLogs, trunks);
                    if (maxLogs == trunks) {
                        tallestTree = plant;
                    }
                    if (plantRaw->max_trunk_height*plantRaw->max_trunk_diameter <= trunks) {
                        doneGrowing.push_back(plant);
                    }
                }

            }
        }
        //markPlant(tallestTree);
        for (auto & plant : doneGrowing) {
            markPlant(plant);
        }

    }
    return CR_OK;
}

DFhackCExport command_result plugin_init(color_ostream &out, std::vector <PluginCommand> &commands) {
    commands.push_back(
        PluginCommand(
            "talltree",
            "Cuts down the non fruit trees that will give the most wood, and the ones that are done growing\n",
            talltree,
            false,
            "Finds the non fruit tree that wil give the most wood and designates it for cutting.\n"
            "Also cuts down all the non fruit trees that are done growing.\n"
        )
    );
    return CR_OK;
}

DFhackCExport command_result plugin_shutdown(color_ostream &out);

DFhackCExport command_result plugin_shutdown(color_ostream &out) {
    return CR_OK;
}

Edit: Needed std::endl
« Last Edit: July 08, 2021, 03:12:04 pm by chickrickepachimecho »
Logged

chickrickepachimecho

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2977 on: July 08, 2021, 03:44:54 pm »

I got the tallest tree. The number of logs for the tree was correct. Not sure on the ginkgos et al yet.

Code: [Select]
command_result talltree(color_ostream &out, std::vector<std::string> & params) {
    // Suspend the core before changing internal data
    CoreSuspender suspend;
    out << ("Valid?") << std::endl;
    if (Maps::IsValid()) {
        const df::plant_raw *plantRaw;
        bool chop = true;
        int maxLogs = 0;
        df::plant* tallestTree = 0;
        std::vector<df::plant*> doneGrowing{};
        for (auto & plant : world->plants.all) {
            chop = true;
            int x = plant->pos.x % 16;
            int y = plant->pos.y % 16;
            df::map_block* tileBlock = Maps::getTileBlock(plant->pos);
            if (tileBlock) {
                df::tiletype_material material = tileMaterial(tileBlock->tiletype[x][y]);
                if (material != df::tiletype_material::TREE ||
                    tileBlock->designation[x][y].bits.hidden) {
                    chop = false;
                }
            }
            else {
                chop = false;
            }
            if (plant->flags.bits.is_shrub) {
                chop = false;
            }
            else {
                plantRaw = df::plant_raw::find(plant->material);
                if (plantRaw->material_defs.type[plant_material_def::drink] != -1) {
                    chop = false;
                }
                for (auto material : plantRaw->material) {
                    if (material->flags.is_set(material_flags::EDIBLE_RAW) ||
                        material->flags.is_set(material_flags::EDIBLE_COOKED)) {
                        chop = false;
                    }
                }
                if (chop) {
                    df::plant_tree_tile** tiles = plant->tree_info->body;
                    df::plant_tree_tile* tilesRow;
                    int trunks = 0;
                    for (int i = 0; i < plant->tree_info->body_height; i++) {
                        tilesRow = tiles[i];
                        for (int j = 0; j < plant->tree_info->dim_y*plant->tree_info->dim_x; j++) {
                            trunks += tilesRow[j].bits.trunk;
                        }
                    }
                    out << "Trunks: " << trunks << std::endl;;
                    maxLogs = std::max(maxLogs, trunks);
                    if (maxLogs == trunks) {
                        tallestTree = plant;
                    }
                    if (plantRaw->max_trunk_height*plantRaw->max_trunk_diameter*plantRaw->max_trunk_diameter <= trunks) {
                        doneGrowing.push_back(plant);
                    }
                }
            }
        }
        markPlant(tallestTree);
        /*
        for (auto & plant : doneGrowing) {
            markPlant(plant);
        }
        */
    }
    return CR_OK;
}

The problem now is that pretty much all trees are getting marked as done growing.

Code: [Select]
plantRaw->max_trunk_height*plantRaw->max_trunk_diameter*plantRaw->max_trunk_diameter <= trunks
max_trunk_height and max_trunk_diameter must not be what I think they are. Does anyone know how to see if a tree is done growing?
« Last Edit: July 08, 2021, 06:33:34 pm by chickrickepachimecho »
Logged

chickrickepachimecho

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2978 on: July 08, 2021, 06:35:18 pm »

If you are writing code to programmatically chop down trees then I am intrigued and would like to subscribe to your newsletter. This is the last bit of missing functionality from my dig-now plugin.

I was able to chop down the tallest non fruiting tree using the code above.
Logged

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2979 on: July 09, 2021, 12:56:52 am »

If you are writing code to programmatically chop down trees then I am intrigued and would like to subscribe to your newsletter. This is the last bit of missing functionality from my dig-now plugin.

I've made some progress on reverse engineering that:
Code: [Select]
void chopTree(int32_t x, int32_t y, int32_t z, df::unitst &unit) //might take more parameters
{
int32_t unit_dis_x = (x - unit->pos.x);
int32_t unit_dis_y = (y - unit->pos.y);
auto plant = dfhack.maps.getPlantAtTile(x,y,z);
if (plant == NULL)
return;

auto tree = plant->tree_info;
if (tree == NULL)
return;

int32_t tree_min_x = plant->pos.x - (tree->dim_x / 2);
int32_t tree_min_y = plant->pos.y - (tree->dim_y / 2);
int32_t tree_min_z = plant->pos.z;
int32_t tree_max_x = (tree->dim_x - 1) + tree_min_x;
int32_t tree_max_y = (tree->dim_y - 1) + tree_min_y;
int32_t tree_max_z = (tree_min_z - 1) + tree->body_height;

for (int32_t loop_x=0, tile_x=tree_min_x; loop_x < tree->dim_x; loop_x++, tile_x++)
{
for (int32_t loop_y=0, tile_y=tree_min_y; loop_y < tree->dim_y; loop_y++, tile_y++)
{
for (int32_t loop_z=(tree->body_height-1), tile_z=tree_max_z; loop_z >= 0; loop_z--, tile_z--)
{
if (tree->body[loop_z][(tree->dim_x * loop_y) + loop_x].trunk == false)
continue;
int32_t mat = plant->material;
if (mat < 0)
continue;
auto raw_plants = df->global->world->raws->plants->all;
if (mat >= raw_plants.size())
continue;
auto plant_raw = raw_plants[mat];
int32_t mattype = plant_raw->material_defs.type[plant_material_def::tree];
int32_t matindex = plant_raw->material_defs.idx[plant_material_def::tree];
if (mattype == -1)
continue;
//need to update item counts and fulfill mandates
//auto log = createItem(-1,item_type::WOOD,mattype,matindex); //function has more parameters than this
log->pos.x = tile_x;
log->pos.y = tile_y;
log->pos.z = tile_z;
//need to create new df::item_projst;
proj->origin_pos.x = tile_x;
proj->origin_pos.y = tile_y;
proj->origin_pos.z = tile_z;
proj->prev_pos.x = tile_x;
proj->prev_pos.y = tile_y;
proj->prev_pos.z = tile_z;
proj->item = log;
proj->cur_pos.x = tile_x;
proj->cur_pos.y = tile_y;
proj->cur_pos.z = tile_z;
//insert proj.id into log general_ref
proj->firer = unit;
//set no_impact_destroy|bouncing|piercing|parabolic|unk9|no_collide:
proj->flags.whole |= 0xB15;
proj->pos_x = 0;
//proj->pos_y = 0; //this isn't used?
proj->pos_z = 0;
proj->speed_x = unit_dis_x * 10000;
proj->speed_y = unit_dis_y * 10000;
proj->speed_z = 0;
//proj->accel_x = 0; //this isn't used?
proj->accel_y = 0;
//proj->accel_z = 0; //this isn't used?
//need to calculate proj->hit_rating
log->flags.in_job = true;
}
}
}
}
//need to handle tiletypes, etc. It's in a separate loop for some reason.
(They aren't all int32_t, I just didn't bother to double check.)

Unfortunately, I haven't gotten to the tiletypes part yet. I got distracted by item creation logic, which leads to fulfilling mandates, which leads to adding good thoughts to nobles...

On the plus side, we might be able to create items without a unit if I keep digging in that direction.
« Last Edit: July 09, 2021, 03:26:17 am by Bumber »
Logged
Reading his name would trigger it. Thinking of him would trigger it. No other circumstances would trigger it- it was strictly related to the concept of Bill Clinton entering the conscious mind.

THE xTROLL FUR SOCKx RUSE WAS A........... DISTACTION        the carp HAVE the wagon

A wizard has turned you into a wagon. This was inevitable (Y/y)?

PatrikLundell

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2980 on: July 09, 2021, 01:46:41 am »

How do you go about debugging a plugin that crashes? So far, I've been commenting code out, but I would like a faster way.
Start the game, hook up a debugger to it, and catch the crash (or set up a breakpoint at the plugin entry and single step through the code).
If, for whatever reason, you don't (want to) use a debugger, I'd try to add trace printouts.

As an aside, I'd consider updating posts with additional info rather than multiposting.
Logged

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2981 on: July 09, 2021, 03:08:03 am »

Does anyone know how to see if a tree is done growing?

Consider using the plant's age? Counting trunk tiles isn't going to work for that because tree growth can be stunted due to obstacles, including other trees. (In addition to any randomness in layout.)
« Last Edit: July 09, 2021, 03:12:56 am by Bumber »
Logged
Reading his name would trigger it. Thinking of him would trigger it. No other circumstances would trigger it- it was strictly related to the concept of Bill Clinton entering the conscious mind.

THE xTROLL FUR SOCKx RUSE WAS A........... DISTACTION        the carp HAVE the wagon

A wizard has turned you into a wagon. This was inevitable (Y/y)?

chickrickepachimecho

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2982 on: July 09, 2021, 08:15:27 am »

Does anyone know how to see if a tree is done growing?

Consider using the plant's age? Counting trunk tiles isn't going to work for that because tree growth can be stunted due to obstacles, including other trees. (In addition to any randomness in layout.)

Yea, I was able to find plant.grow_counter, but am not sure what values it would have when a tree is done growing. It probably would not be the same for every tree according to the wiki, but I am not sure where to find the info for every tree. It's possible to check if a tree is being blocked using plant.plant_tree_info.plant_tree_tile.blocked. Once I understand how trunk branching works, it should be possible to take blocking into account.

Also, counting trunks is weird. Birch has a max trunk height of 8, but there is one with a trunk height of 10. Same with alder. Birch and alder have trunk branchings of 0, so perhaps trees can have 2 extra trunks acting like end points rather than contributing to the height.

Plus, willow's max trunk diameter is 1, but there is a willow which appears to have a trunk diameter of 3. This appears to be due to a trunk branching of 2. I wonder if this means a willow could have trunks in a 25 tile square, giving the appearance of having a trunk diameter of 5. There is a larch that kind of confirms this, and it appears the branching can happen every z-level, increasing the diameter of the branching area. It would probably be easier just to check that a tree has reached max height + 2 than to figure out how branching works.

As for the other plugin I want to create that will replace worn clothes. It appears that worn clothes getWear value go from 1 to 4, at the least, based on code, and 0 means no wear. The code does not show whether there is an upper limit, but that 4 and 5 would have the same wear label. At what point is worn clothing scrapped by a dwarf?
« Last Edit: July 09, 2021, 08:39:14 pm by chickrickepachimecho »
Logged

lethosor

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #2983 on: July 09, 2021, 09:38:28 pm »

New release! https://github.com/DFHack/dfhack/releases/tag/0.47.05-r2

I have a bit of catching up to do - I'll reply to a couple questions in a separate post.
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.

lethosor

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r1
« Reply #2984 on: July 09, 2021, 09:58:23 pm »

As a starting point for the first one, here's one of my scripts intended to control which trees to cut, sparing one of each resource providing kind of tree, selecting the ones closest to the center of the embark. It skips cavern trees, and deals with elven logging restrictions.
Code: [Select]
<snip>
                  if trees_designated < max_trees then
                    cur.designation [x % 16] [y % 16].dig = df.tile_dig_designation.Default
                    cur.flags.designated = true
I would recommend using `dfhack.designations.markPlant()` instead - it does the same thing, but the inverse, `unmarkPlant()`, is significantly more complicated and it's good to use library functions for consistency. This one admittedly seems to be missing from the Lua API docs.

Incidentally, autochop already uses these library functions, so there wouldn't be any change necessary there.

Or you could point me to a list of all the possible methods or objects within "unit", because I can't find it.

The source of the structure descriptions we use is in XML form at https://github.com/dfhack/df-structures/ - it is a bit tricky to parse if you're unfamiliar with it. The definition for the "unit" type in 0.47.05-r2 starts here: https://github.com/DFHack/df-structures/blob/0.47.05-r2/df.units.xml#L587

As a more interactive alternative, I might suggest gui/gm-editor. Running it with a unit selected will give you a UI that lets you navigate all fields of a unit, including sub-structs. There are some other useful features that you can see by pressing "?".

Is there a way to use this struct

Code: [Select]
  struct DFHACK_EXPORT plant_tree_info {
<snip>
to find the number of logs that the tree will produce?
This recent script by Bumber might be useful as a reference to figure out how to interpret and count the number of tiles in the structure. I don't know if the number of logs produced by a tree corresponds exactly to anything (e.g. the number of trunk tiles), but there's a chance it does, or that it's close.

Edit: it seems that you all have figured out that it's more complicated. I mainly just wanted to track down this script again. Carry on!

How do you go about debugging a plugin that crashes? So far, I've been commenting code out, but I would like a faster way.
That depends - what platform are you developing on?

For instance, https://docs.dfhack.org/en/0.47.05-r2/docs/Memory-research.html#gdb (perhaps not the best page for this) explains how to use GDB on Linux.
Logged
DFHack - Dwarf Manipulator (Lua) - DF Wiki talk

There was a typo in the siegers' campfire code. When the fires went out, so did the game.
Pages: 1 ... 197 198 [199] 200 201 ... 243