-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use colony for map and vehicle item storage #31406
Conversation
ac90687
to
bbff510
Compare
That's not true. But thanks for working on this :). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking promising. This is indeed nice cleanup. Hope this wasn't too soon to do a preliminary review :).
Have you tackled/tested activity serialization yet? Didn't see anything related to that as I perused.
const item &get_uppermost_item() const { | ||
return sm->itm[x][y].back(); | ||
return *std::prev( sm->itm[x][y].cend() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I imagine this get_uppermost_item
is used e.g. for map rendering. Using the last item for that made sense when newly dropped items were always put to the back, but less so now. We probably want to eventually remove this and e.g. get the largest item on the square to render instead. But not in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's exactly what it's for.
And yeah that's for a future PR. I've also considered rewriting some of the inventory code to display alphabetically since storage on the map is no longer ordered.
Um, yeah may not have totally thought that one through. The meat of this PR is turning out to be not swapping in the colony but getting rid of all indexes to items on the map and vehicles. |
Haven't yet and it works fine for now since |
Oh, another thing: if you can, it may be worth checking memory consumption impact of these changes. An |
|
||
// We have a valid target, so preform the full finish function | ||
// instead of just selecting the next valid target | ||
act.index = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IS act.index
a bool
? It seems unlikely...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see later that you are treating it as a bool
. I can't decide whether it's clearer to assign 0
or false
here. Hmm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I agree that it's not super clean. I considered adding either a bool
or an std::vector<bool>
to player_activity
but decided that was outside the scope of this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have an aspiration to make accessing things inside player_activity
cleaner in general, with some vague ideas of how to go about it. Looking at your code here makes me want to get to that, but I probably won't soon.
item_location &target = act->targets.back(); | ||
|
||
// Corpses can disappear (rezzing!), so check for that | ||
if( !target || !target->is_corpse() ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The operator bool
on item_location
is definitely doing the wrong thing in general. That's not really your fault, but this can totally end up pointing at the wrong item (I think there have been bug reports about butchery doing that already). I think the only way to fix this sensibly is with the weak_ptr
idea Kevin has discussed. But that's orthogonal to your changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what it's doing is actually OK here for now. It just searches at its stored location for an item matching its stored pointer, returning true if such an item is found.
I agree theweak_ptr
plan is definitely a lot cleaner and more robust and may look at implementing that once this get wrapped up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bear in mind that colony
deliberately tries to reuse memory, so there is a good chance that there will be some different item
at the same address if one is removed and another added, and it has no way to tell the difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but I don't think there's anything we can do about it yet without the weak_ptr
trick aside from hope it's not a corpse.
the invlet tests are currently broken, will look into a fix. |
e0520de
to
460a8c2
Compare
This PR is virtually complete now. The only remaining major task is a rewrite of |
d276aa8
to
d8f0cb1
Compare
const item &seed = farm_map.i_at( pos ).front(); | ||
if( farm_valid_seed( seed ) ) { | ||
if( farm_map.furn( pos ) == f_plant_harvest ) { | ||
// Can't use item_stack::only_item() since there might be fertilizer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this is a concern? I don't think fertilizer actually gets added as an item on the tile; it just modifies the time to mature.
On the subject of unrelated bugs, I see this is checking specifically for f_plant_harvest
, whereas it probably ought to be doing something more generic now, because there are other harvestable furnitures, I think. You don't have to fix that on this PR, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be checking for the GROWTH_HARVEST
flag, but it looks as though this whole thing is largely a duplicate of iexamine::harvest
, and is out of date with the current state of what iexamine::harvest
does.
Which belongs in a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function led me to believe that fertilizer stays on the tile. It could also easily be outdated though.
Cataclysm-DDA/src/iexamine.cpp
Lines 2066 to 2082 in 4d34142
ret_val<bool> iexamine::can_fertilize( player &p, const tripoint &tile, | |
const itype_id &fertilizer ) | |
{ | |
if( !g->m.has_flag_furn( "PLANT", tile ) ) { | |
return ret_val<bool>::make_failure( _( "Tile isn't a plant" ) ); | |
} | |
if( g->m.i_at( tile ).size() > 1 ) { | |
return ret_val<bool>::make_failure( _( "Tile is already fertilized" ) ); | |
} | |
if( !p.has_charges( fertilizer, 1 ) ) { | |
return ret_val<bool>::make_failure( | |
_( "Tried to fertilize with %s, but player doesn't have any." ), | |
fertilizer.c_str() ); | |
} | |
return ret_val<bool>::make_success(); | |
} |
And we can see it gets added here
Cataclysm-DDA/src/iexamine.cpp
Line 2106 in 4d34142
g->m.spawn_item( tile, "fertilizer", 1, 1, calendar::turn ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I did read iexamine::fertilize_plant
but I missed that line.
Alright, I think this is ready to go. The new invlet test uses a hack to enable item UUIDs, but It seems to actually be more robust than what we had previously as the old test was giving false positives after #30603. Sorry that this is so large. If needed there are some parts that I could probably break off, but I wont have time to do so for a couple days. |
41151cd
to
a4481bf
Compare
Added a comment explaining why the unique id hack was implemented the way it is using |
Some rough numbers for the performance gains of Low number of active items: Lots of active items: Profiling was done while waiting with active items strewn about the map The next target for optimizing item processing is |
Profiling results part 2, Memory usage:A worst case scenario for colony is 1 item per tile as the minimum group size is 8. I tested this case by spawning and killing 2600 moose, to create a one corpse per tile test case. Memory usage of Why is it not exactly 8 times higher?I haven't looked into the gritty details, but colony has more memory overhead than just the stored types to increase performance. For example, there is a list to keep track of which elements have been erased so those memory locations can be reused for future insertion. What can we do to mitigate this?The simplest option is setting the starting group size to something less than 8 (minimum of 3). I haven't looked into how this would effect performance yet, but will do some investigation. Another option would be to store one Do we need to do something about this?I'm not sure, the memory usage isn't crazy and the current setup is probably better for performance than optimizing for lower memory usage. Up to @kevingranade though really. Regardless, I'd like to address that issue (if needed) in a follow up PR assuming that this is acceptable to merge as is. |
Thanks for testing that. Another option is to look into making the |
a4481bf
to
ae9ae28
Compare
Conflicts resolved |
You wish :) |
colony has a better memory layout and faster random access than the previous std::list while mantaining pointer/iterator stability
The goal here is to remove all raw indexes to items on the map or in vehicles as indexes to colonies are unstable while pointers and iterators are stable. In this commit ACT_MOVE_ITEMS, ACT_PICKUP, and ACT_WEAR were refactored to use item_location with significant code cleanup.
Notably `Pickup::pick_up()` now uses item_stack iterators instead of indexes since the previous hack proved to be too fragile. Since items are now stored unordered on the map, the order of items displayed in the pickup ui is now sorted using `item::operator<()`
Indexes to a colony are not stable through insertion/erasure and should be avoided for everything except serialization
Indexes to colonies are unstable and everything has now been converted to use iterators and pointers. Also fixed a few minor style issues and typos.
"front" no longer makes sense since items in a colony are unordered. The new function gives a debug message if there is not exactly one item at the location. Also fixed a few bugs caused by previous refactoring and caught in code review
Rewrite the item management of the the invlet test to use an item unique id hack to make it more robust and functional now that items on the map are unordered. Note: this test seems to have been giving false positives since CleverRaven#30603 was merged, since the AUTO_INV_ASSIGN option was not being properly set. This only became apparent after implementing the more robust item management code with unique ids. This also fixes a few remaing calls in the tests to a removed vehicle function which still compiled due to implicit conversion of 0 to a pointer.
ae9ae28
to
3922cca
Compare
Look again :) |
After CleverRaven#31796 item processing invalidates item_locations, which causes issues with all activities using item_locations. This commit rewrites active_item_cache to store a safe_reference<item> instead of an item_stack::iterator, removing the now unnecessary active_item_set and has() functions. This also fixes a bug with active item reording after processing introduced by CleverRaven#31406 and a minor bug with the submaps_with_active_items cache.
After CleverRaven#31796 item processing invalidates item_locations, which causes issues with all activities using item_locations. This commit rewrites active_item_cache to store a safe_reference<item> instead of an item_stack::iterator, removing the now unnecessary active_item_set and has() functions. This also fixes a bug with active item reordering after processing introduced by CleverRaven#31406 and a minor bug with the submaps_with_active_items cache.
* Rework active_item_cache to use safe references After #31796 item processing invalidates item_locations, which causes issues with all activities using item_locations. This commit rewrites active_item_cache to store a safe_reference<item> instead of an item_stack::iterator, removing the now unnecessary active_item_set and has() functions. This also fixes a bug with active item reordering after processing introduced by #31406 and a minor bug with the submaps_with_active_items cache. * Make changes from code review In particular increment the iterator properly in active_item_cache::get() * Remove redundant get() calls on safe references clang-tidy told me what to do
} | ||
|
||
case HARVEST_SAP: { | ||
liquid_handler::handle_liquid_from_container( *container, PICKUP_RANGE ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like *container
can be a nullptr
and there is no check for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This option is only available if has_sap
is true, and has_sap
can only be true if a container was found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not saying this code isn't fragile and prone to break at some point, but it is currently correct I believe.
Summary
SUMMARY: Infrastructure "Use colony for map and vehicle item storage."
Purpose of change
As described in #31338, colony has several advantages over the current
std::list
, the most important being that iterators are not invalidated by erasure. This will make the item management code much more stable and has already cleaned up one nasty hack with processing activity items.Describe the solution
std::list<item>
stored in submaps and vehicle parts with acolony<item>
.item_stack
to reflect this change.item_stack::operator[]
and refactorinvlet_test.cpp
Additional context
I've done my best to Include What I Use, but I've certainly missed some includes. Maybe I will try and get the IWYU tooling set up when this is done.