From aecb32c4b45b414114649bec947ce20dd9569a16 Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 15 May 2025 12:17:16 -0400 Subject: [PATCH] Make stack merging much less of a potential lagfest (#91015) --- code/game/objects/items/stacks/stack.dm | 63 +++++++++++++++---------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 3cf2c637d7f..9a5862ca54a 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -83,6 +83,9 @@ . = ..() + if(merge) + . = INITIALIZE_HINT_LATELOAD + var/materials_mult = amount if(LAZYLEN(mat_override)) materials_mult *= mat_amt @@ -90,15 +93,6 @@ if(LAZYLEN(mats_per_unit)) initialize_materials(mats_per_unit, materials_mult) - if(merge) - for(var/obj/item/stack/item_stack in loc) - if(item_stack == src) - continue - if(can_merge(item_stack)) - INVOKE_ASYNC(src, PROC_REF(merge_without_del), item_stack) - if(is_zero_amount(delete_if_zero = FALSE)) - return INITIALIZE_HINT_QDEL - recipes = get_main_recipes().Copy() if(material_type) var/datum/material/what_are_we_made_of = GET_MATERIAL_REF(material_type) //First/main material @@ -111,19 +105,51 @@ update_weight() update_appearance() - var/static/list/loc_connections = list( - COMSIG_ATOM_ENTERED = PROC_REF(on_movable_entered_occupied_turf), - ) - AddElement(/datum/element/connect_loc, loc_connections) if(is_path_in_list(merge_type, GLOB.golem_stack_food_directory)) AddComponent(/datum/component/golem_food, golem_food_key = merge_type) +/obj/item/stack/LateInitialize() + merge_with_loc() + +/obj/item/stack/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + if((!throwing || throwing.target_turf == loc) && old_loc != loc && (flags_1 & INITIALIZED_1)) + merge_with_loc() + ///Called to lazily update the materials of the item whenever the used or if more is added /obj/item/stack/proc/update_custom_materials() if(length(mats_per_unit)) set_custom_materials(mats_per_unit, amount) +/obj/item/stack/proc/find_other_stack(list/already_found) + if(QDELETED(src) || isnull(loc)) + return + for(var/obj/item/stack/item_stack in loc) + if(item_stack == src || QDELING(item_stack) || (item_stack.amount >= item_stack.max_amount)) + continue + if(!(item_stack.flags_1 & INITIALIZED_1)) + stack_trace("find_other_stack found uninitialized stack in loc? skipping for now") + continue + var/stack_ref = REF(item_stack) + if(already_found[stack_ref]) + continue + if(can_merge(item_stack)) + already_found[stack_ref] = TRUE + return item_stack + +/// Tries to merge the stack with everything on the same tile. +/obj/item/stack/proc/merge_with_loc() + var/list/already_found = list() // change to alist whenever dreamchecker and such finally supports that + var/obj/item/other_stack = find_other_stack(already_found) + var/sanity = max_amount // just in case + while(other_stack && sanity > 0) + sanity-- + if(merge(other_stack)) + return FALSE + other_stack = find_other_stack(already_found) + return TRUE + /obj/item/stack/apply_material_effects(list/materials) . = ..() if(amount) @@ -662,17 +688,6 @@ . = merge_without_del(target_stack, limit) is_zero_amount(delete_if_zero = TRUE) -/// Signal handler for connect_loc element. Called when a movable enters the turf we're currently occupying. Merges if possible. -/obj/item/stack/proc/on_movable_entered_occupied_turf(datum/source, atom/movable/arrived) - SIGNAL_HANDLER - - // Edge case. This signal will also be sent when src has entered the turf. Don't want to merge with ourselves. - if(arrived == src) - return - - if(!arrived.throwing && can_merge(arrived)) - INVOKE_ASYNC(src, PROC_REF(merge), arrived) - /obj/item/stack/hitby(atom/movable/hitting, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) if(can_merge(hitting, inhand = TRUE)) merge(hitting)