Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 ... 200 201 [202] 203 204 ... 243

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

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3015 on: July 23, 2021, 12:27:48 pm »

what is the nicest way to check from Lua if a structure has a field?

Code: [Select]
if gref.unit_id != nil and gref.unit_id == some_unit_id thenDoes this work? (I think it might still work if you remove "!= nil", unless it breaks when unit_id == 0.)



Spatters on a plant should be removed together with the plant it's tied to. If the spatter resides in a different place and the vector just refers to them, you should locate that place and remove them from there [...]

I'm just going with the code I disassembled. If it's removed from the map block (or wherever,) it's not done in the plant deconstructor. (Probably while changing the tiletype, which is different between shrubs/saplings and trees.)

The disassembly just uses the "free" syscall on the vector's memory range.




Beautiful.
« Last Edit: July 23, 2021, 01:51:27 pm 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)?

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3016 on: July 23, 2021, 02:10:10 pm »

what is the nicest way to check from Lua if a structure has a field?

Code: [Select]
if gref.unit_id != nil and gref.unit_id == some_unit_id thenDoes this work? (I think it might still work if you remove "!= nil", unless it breaks when unit_id == 0.)


No, it runs into the very same problem: if there is no "unit_id" in the gref, the current implementation of `__index` throws an exception.
Logged

lethosor

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3017 on: July 23, 2021, 05:39:57 pm »

what is the nicest way to check from Lua if a structure has a field?

I want the following loop.
Code: [Select]
for j, gref in ipairs(posting.job.general_refs) do
if gref.unit_id == some_unit_id then
do_stuff
end
end
but I don't know what gref is going to be. If it's general_ref_unit_slaughtereest or general_ref_unit_workerst, it has unit_id, but general_ref_building_holderst doesn't.

In current form, the loop throws
Quote
Cannot read field general_ref_building_holderst.unit_id: not found.
stack traceback:
        [C]: in metamethod '__index'
The usual solution is to use pcall() around a function that just accesses the field, then handle any errors as you see fit. For example:
Code: [Select]
local ok, val = pcall(function()
  return gref.unit_id
end)
Feel free to use better variable names, of course. Docs for pcall() can be found here: https://www.lua.org/manual/5.3/manual.html#pdf-pcall

This might not be very performant. If you run into bottlenecks, I don't believe there is a way to look up what fields a given type has from Lua (although the C++ layer that __index calls definitely has this information), but you could build a table of "type => fields" or "type => has_unit_id_field" mappings yourself, or cache it as you go.

Quote
Ideally, it would just return nil in this case, but this may be too much to ask :)
I think it would be too big of a compatibility break at this point. I think the behavior is mostly for parity with other languages where accessing an invalid field throws an error. Granted, in C++, that error occurs at compile-time, but in Ruby it would occur at runtime like in Lua. There's also the matter of existing fields that can be defined but nil (i.e. null pointers in C++), which the current behavior makes more clear to Lua.
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.

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3018 on: July 24, 2021, 03:20:09 am »

what is the nicest way to check from Lua if a structure has a field?
I don't believe there is a way to look up what fields a given type has from Lua (although the C++ layer that __index calls definitely has this information), but you could build a table of "type => fields" or "type => has_unit_id_field" mappings yourself, or cache it as you go.
What I was hoping for is access to the same information __index has in some form. Usually, the place to look would be the metatable of the object, but it's a string in this case. But maybe we could have some meta-info in the basic type structures in the df-table, so we can do something like the following.
Code: [Select]
if df[getmetatable(gref)].fields.unit_id then
     print('Has unit_id field!')
end
The getmetatable(gref) is here a string like "general_ref_building_holderst".

And, I mean, we already kind of have this info, just not in a clean way.
Code: [Select]
local function getFieldOrNil(obj, field)
for k,v in pairs(obj) do
if k == field then
return v
end
end
return nil
end

if getFieldOrNil(gref, 'unit_id') == unit.id then
doStuff()
end
Logged

Fleeting Frames

  • Bay Watcher
  • Spooky cart at distance
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3019 on: July 24, 2021, 05:07:13 am »

Yeah, I use something like that alongside building a table for what was already checked
Code: [Select]
(function getFlag(dfvalue, key)
    -- Utility function for safely requesting info from df data
    if not dfvalue or not key then return nil end --pairs crash prevention
    flagtypetable = flagtypetable or {} --memoization so it doesn't iterate through the dfvalue if we've already checked that type of value for given flag
    if flagtypetable[dfvalue._type] and flagtypetable[dfvalue._type][key] then return dfvalue[key] end
    if flagtypetable[dfvalue._type] and flagtypetable[dfvalue._type][key]==false then return nil end
    if not flagtypetable[dfvalue._type] then flagtypetable[dfvalue._type] = {} end
    for akey, avalue in pairs(dfvalue) do
        if akey == key then
            flagtypetable[dfvalue._type][key] = true
            return dfvalue[akey]
        end
    end
    flagtypetable[dfvalue._type][key] = false
end
The first lookup will iterate, further lookups will be just function calls that checks table.

I think there might have been some cases where memoriziation was undesirable, but don't recall them right now.

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3020 on: July 24, 2021, 07:22:18 am »

Yeah, I use something like that alongside building a table for what was already checked

I think there might have been some cases where memoriziation was undesirable, but don't recall them right now.

Thanks, I'll use this.
Logged

Quietust

  • Bay Watcher
  • Does not suffer fools gladly
    • View Profile
    • QMT Productions
Re: DFHack 0.47.05-r2
« Reply #3021 on: July 25, 2021, 11:42:02 am »

what is the nicest way to check from Lua if a structure has a field?

I want the following loop.
Code: [Select]
for j, gref in ipairs(posting.job.general_refs) do
if gref.unit_id == some_unit_id then
do_stuff
end
end
but I don't know what gref is going to be. If it's general_ref_unit_slaughtereest or general_ref_unit_workerst, it has unit_id, but general_ref_building_holderst doesn't.
If you're not performing the check very often, you might be better off just calling gref:getUnit() and examining the value returned - if it's a reference to a unit, it will give you a pointer to the unit itself (and you can then check its ID accordingly), and if it's a reference to something else you'll get a null pointer instead.
Logged
P.S. If you don't get this note, let me know and I'll write you another.
It's amazing how dwarves can make a stack of bones completely waterproof and magmaproof.
It's amazing how they can make an entire floodgate out of the bones of 2 cats.

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3022 on: July 25, 2021, 12:19:42 pm »

what is the nicest way to check from Lua if a structure has a field?

I want the following loop.
Code: [Select]
for j, gref in ipairs(posting.job.general_refs) do
if gref.unit_id == some_unit_id then
do_stuff
end
end
but I don't know what gref is going to be. If it's general_ref_unit_slaughtereest or general_ref_unit_workerst, it has unit_id, but general_ref_building_holderst doesn't.
If you're not performing the check very often, you might be better off just calling gref:getUnit() and examining the value returned - if it's a reference to a unit, it will give you a pointer to the unit itself (and you can then check its ID accordingly), and if it's a reference to something else you'll get a null pointer instead.

Well, this is definitely better.

Although it begs the question: how would I discover this function on my own? There is no mention in the Lua API doc, getmetatable(gref) is a string, df.general_ref is of no help either.
Logged

Quietust

  • Bay Watcher
  • Does not suffer fools gladly
    • View Profile
    • QMT Productions
Re: DFHack 0.47.05-r2
« Reply #3023 on: July 25, 2021, 01:57:23 pm »

how would I discover this function on my own? There is no mention in the Lua API doc, getmetatable(gref) is a string, df.general_ref is of no help either.
You would discover this function by looking at the structure definitions - in this specific case, you would have found it here.
Logged
P.S. If you don't get this note, let me know and I'll write you another.
It's amazing how dwarves can make a stack of bones completely waterproof and magmaproof.
It's amazing how they can make an entire floodgate out of the bones of 2 cats.

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3024 on: July 26, 2021, 02:16:11 am »

how would I discover this function on my own? There is no mention in the Lua API doc, getmetatable(gref) is a string, df.general_ref is of no help either.
You would discover this function by looking at the structure definitions - in this specific case, you would have found it here.

Oh wow, thanks for that - I haven't even thought structure definitions would have functions in them!
Logged

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3025 on: July 28, 2021, 04:03:07 pm »

I have a question about jobs. I have an onJobCompleted-handler with "The job that is passed to this function is a copy". It looks something like this.

Code: [Select]
<job: 000001D919322E30>
id                      = 37238
list_link               = nil
posting_index           = -1
completion_timer        = 0
unk4                    = 0
flags                   = <job_flags: 000001D919322E5C>
    working                 = true
    by_manager              = true
expire_timer            = 0
recheck_cntdn           = 0
wait_timer              = 0
unk11                   = -1
order_id                = 192

It is not part of the df.global.world.jobs.list and is probably destroyed after the event handler is done. I'd like to convert it to an actual active once again job. Comparing this job with a fresh one, I notice following differences: working is not set (which is trivial to achieve), posting_index is not -1 and also list_link is not nil.

The question is how do I append a job to the df.global.world.jobs.list from Lua correctly and how do I (and should I) find a posting for it?
Logged

Atkana

  • Bay Watcher
  • [CURIOUSBEAST]
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3026 on: July 29, 2021, 01:35:02 am »

The question is how do I append a job to the df.global.world.jobs.list from Lua correctly and how do I (and should I) find a posting for it?
Luckily for you, I've got a job helper script I never finished just sitting around :P

For appending the job, use dfhack's dfhack.job.linkIntoWorld function (see this section of the docs).

For making a posting, you only need to do that if you want to advertise it as available for a unit to take. If you're manually assigning a unit to the job, you won't need to make a posting. This is the code I was using, but it might not be the best way.
Code: [Select]
-- I don't fully understand how this works, so this might be horribly wrong
-- The DF job assigner needs a job to be in postings for it to automatically be assigned to a unit.
function addJobToPostings(job)
local addedIndex = false
-- Find the first free empty postings to add a job to
for index, posting in ipairs(df.global.world.jobs.postings) do
if posting.job == nil then
-- It's free real estate!
posting.job = job
posting.anon_1 = 0
posting.flags.dead = false

job.posting_index = posting.idx
addedIndex = posting.idx
break
end
end
if addedIndex then
print("Added job " .. job.id .. " to postings as index " .. addedIndex)
else
print("Couldn't find posting slot to add in job " .. job.id)
end

return addedIndex
end

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3027 on: July 29, 2021, 02:34:57 am »

The question is how do I append a job to the df.global.world.jobs.list from Lua correctly and how do I (and should I) find a posting for it?
Luckily for you, I've got a job helper script I never finished just sitting around :P

For appending the job, use dfhack's dfhack.job.linkIntoWorld function (see this section of the docs).

For making a posting, you only need to do that if you want to advertise it as available for a unit to take. If you're manually assigning a unit to the job, you won't need to make a posting. This is the code I was using, but it might not be the best way.

Nice, thanks. Did you figure what posting.anon_1 does since you are setting it to 0?

And in the rather unlikely case all postings are in use, can we just create a new one?

Another thing I notice I'm missing for what I have in mind: is there a way to find the building the job in onJobCompleted originated from (if there is any)?
Logged

Atkana

  • Bay Watcher
  • [CURIOUSBEAST]
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3028 on: July 30, 2021, 02:03:57 am »

Nice, thanks. Did you figure what posting.anon_1 does since you are setting it to 0?
I don't think so (?). I likely just copied what I saw happening in regular jobs I was checking and hoped for the best :P The comment in the structs says "not saved" - I'm not sure if that means that value is never saved (and so is useless) or if it's supposed to be some flag determining if the job is saved or not (yay ambiguity).

And in the rather unlikely case all postings are in use, can we just create a new one?
Also not sure on that. The game has a lot of postings available, so it's unlikely to run out. I think I had intended at some point to manually create enough jobs in vanilla to fill all the postings just to see what happens (does the game handle that by preventing you from making new jobs?).

Another thing I notice I'm missing for what I have in mind: is there a way to find the building the job in onJobCompleted originated from (if there is any)?
This is what modtools/reaction-trigger does for getting the unit and building from a job. (tl;dr Find the general ref with type of df.general_ref_type.BUILDING_HOLDER, take building_id from it, then use df.building.find(building_id) to get the building.

Erendir

  • Bay Watcher
    • View Profile
Re: DFHack 0.47.05-r2
« Reply #3029 on: July 30, 2021, 05:06:52 am »

Nice, thanks. Did you figure what posting.anon_1 does since you are setting it to 0?
Another thing I notice I'm missing for what I have in mind: is there a way to find the building the job in onJobCompleted originated from (if there is any)?
This is what modtools/reaction-trigger does for getting the unit and building from a job. (tl;dr Find the general ref with type of df.general_ref_type.BUILDING_HOLDER, take building_id from it, then use df.building.find(building_id) to get the building.
Thanks, I somehow completely missed the job.general_refs. But seeing how reaction-trigger does it makes me wonder: is it better to check gref:getType() == df.general_ref_type.BUILDING_HOLDER or building = gref:getBuilding(); if building then?

On another note, the job from eventful.onJobCompleted kept being destroyed resulting in some strange stuff happening (mostly crashes :))) as I kept trying to use it. The fix was making a clone at the very beginning (job = dfhack.job.cloneJobStruct(job)). So, I'm wondering: is this (job being destroyed after leaving the event handler) by design? The job parameter in eventful.onJobCompleted is already a copy, so it feels kind of strange to make yet another copy of it in order to use it. (But it may be actually is by design because of object ownership and stuff -- if that's the case, pretty please put a note about it in the docs)
Logged
Pages: 1 ... 200 201 [202] 203 204 ... 243