DFHack / dfhack

Memory hacking library for Dwarf Fortress and a set of tools that use it
Other
1.87k stars 472 forks source link

dfhack.units.computeMovementSpeed returns 0 or 10000 only(?). #607

Open bdbryant opened 9 years ago

bdbryant commented 9 years ago

You can see it with my show-speeds.lua script (http://www.bay12forums.com/smf/index.php?topic=136748.0). The screenshot there is from 0.34, and the first column is 100000/dfhack.units.computeMovementSpeed, giving a nominal 10 when the C++ function returns 10000, but getting an actual distribution of values in that screenshot (implying returned values between 0 and 10000).

But with dfhack-0.40.24-r2 and -r3 everyone I've seen so far gets either 10 or inf in the script's output, depending whether the function returns 10000 or 0.

Notice that the last line in the function in library/modules/Units.cpp is return std:min(10000, std:max(0, speed)); which explains where the 10000s and 0s are coming from. Looks like the computation is coming up with speed < 0 or speed > 10000 (or garbage) to get the observed returned values.

lethosor commented 9 years ago

There are a few other places where 0 could be returned - have you verified that none of those conditions are true?

bdbryant commented 9 years ago

No. I'll look at the code some more.

bdbryant commented 9 years ago

I built and installed from the current repository and made some code changes to narrow down where the problem is. (I've never invested the time to learn a debugger.)

There are four returns in the function: three conditional returns right at the top, and the one I previously mentioned right at the bottom.

The following tests were made all starting from the same Dwarf Mode save, which I don't think is the same one I was using when I first posted

Right after the three returns at the top I added a return 1; and got 1 for everyone, so none of my current dorfs are returning 0 due to any of those conditions.

I changed that line to return speed; and then got 0 for everyone, so it looks like craw->misc.speed is where they are picking the zeros up. (It's the only assignment or manipulation of speed before that temporary return.)

I deleted that return and changed the return near the end to a simple return speed; rather than the bounded value, and still get 0 for almost everyone. (One dorf returns a value of 2144, and he turns out to be sleeping.)

Modifications to speed in the code after setting it to craw->misc.speed are either additions or multiplications/divisions. The latter won't make any difference since they are starting with 0 (per above), but the adds could explain why the sleeper gets a higher number. (There is a call to adjust_speed_rating with a sleepiness_timer argument, and that function can provide adds, so maybe that's why the sleeper gets a non-zero value.)

I started a new game, leaving dfhack built to return the raw (unbounded) speed. One individual started with a speed of 50. After unpausing, two more briefly picked up non-zero speeds, but then went back to zero. None showed a job or a curse. I created a stockpile so they would all get busy moving stuff, and all seven speeds went to zero when their jobs were "store item in stockpile". When they went back to idle, all their speeds were zero except one who briefly showed a value of 42.

My best guess at this point is that craw->misc.speed is the problem.

bdbryant commented 9 years ago

BTW, the 2144 is a reasonable speed (based on my experience with 0.34), though IIRC sleepers used to show very slow speeds. The values 42 and 50 represent extremely high speeds. I suspect they represent modifiers added to an incorrect zero base value.

(I just edited the previous post to change "reasonable speeds" to "non-zero speeds" for these numbers.)

lethosor commented 8 years ago

Looks like outdated structures to me, although some field names are correct - here's craw.misc for a random dwarf:

litter_size_min          = 3
litter_size_max          = 1
penetratepower           = 0
vermin_bite_chance       = 0
grasstrample             = 5
buildingdestroyer        = 0
itemcorpse_itemtype      = -17040
itemcorpse_itemsubtype   = -28694
itemcorpse_materialtype  = -17580
itemcorpse_materialindex     = -28694
itemcorpse_quality       = 0
remains_color            = <int16_t[]: 0x1491c0b6>
difficulty               = 1
caste_glowcolor          = <int16_t[]: 0x1491c0be>
beach_frequency          = 0
clutch_size_min          = 1
clutch_size_max          = 3
vision_arc_min           = 60
vision_arc_max           = 120
speed                    = -1880442884
modvalue                 = 1
petvalue                 = 1
milkable                 = 100800
viewrange                = 20
maxage_min               = 150
maxage_max               = 170
baby_age                 = 1
child_age                = 12
swim_speed               = -1880441108
trade_capacity           = 1000
unk4                     = 142
pop_ratio                = 50
adult_size               = 6000
bone_mat                 = 22
bone_matidx              = 465
fish_mat_index           = -1
egg_mat_index            = -1
attack_trigger           = <int32_t[]: 0x1491c118>
egg_size                 = 50
grazer                   = -1
petvalue_divisor         = 1
prone_to_rage            = 0
unk6                     = <int32_t[]: 0x1491c134>
bdbryant commented 8 years ago

Lots of {0,1,2,4,8} in that number. I wonder whether some subset of the bits give the number we want, with the negative coming from a numeric overflow caused by using too many of the bits.

Do you know how the offsets were obtained?

lethosor commented 8 years ago

https://github.com/DFHack/df-structures/blob/1bc4f6133c8a5bbd397001f97647c15724317e07/df.creature-raws.xml#L779-L788 I'm surprised nobody noticed the "no longer used" comments before (they're also in the generated headers, if you're interested). There should be a different way to obtain speed data as of 0.40.01 (with the new gaits, etc.).