From c98c1ee77bc43d98f42bce4dce89fc14d9513a82 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 13 Oct 2020 02:15:26 +0200 Subject: [PATCH] [MIRROR] Fixes crafting duplication bug/runtime and attempts to address destroying items in consumed containers (#1270) * Fixes crafting duplication bug/runtime and attempts to address destroying items in consumed containers * Update global_lists.dm Co-authored-by: Timberpoes Co-authored-by: Azarak --- code/__HELPERS/cmp.dm | 16 ++++++++++++++++ code/__HELPERS/global_lists.dm | 10 +++++++++- code/datums/components/crafting/crafting.dm | 8 ++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index f45504b14f8..8b0ae131482 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -133,3 +133,19 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_mob_realname_dsc(mob/A,mob/B) return sorttext(A.real_name,B.real_name) + +/** + * Sorts crafting recipe requirements before the crafting recipe is inserted into GLOB.crafting_recipes + * + * Prioritises [/datum/reagent] to ensure reagent requirements are always processed first when crafting. + * This prevents any reagent_containers from being consumed before the reagents they contain, which can + * lead to runtimes and item duplication when it happens. + */ +/proc/cmp_crafting_req_priority(var/A, var/B) + var/lhs + var/rhs + + lhs = ispath(A, /datum/reagent) ? 0 : 1 + rhs = ispath(B, /datum/reagent) ? 0 : 1 + + return lhs - rhs diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 5835d303629..9625b0ca24c 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -54,8 +54,16 @@ GLOB.emote_list = init_emote_list() - init_subtypes(/datum/crafting_recipe, GLOB.crafting_recipes) make_skyrat_datum_references() //SKYRAT EDIT ADDITION - CUSTOMIZATION + init_crafting_recipes(GLOB.crafting_recipes) + +/// Inits the crafting recipe list, sorting crafting recipe requirements in the process. +/proc/init_crafting_recipes(list/crafting_recipes) + for(var/path in subtypesof(/datum/crafting_recipe)) + var/datum/crafting_recipe/recipe = new path() + recipe.reqs = sortList(recipe.reqs, /proc/cmp_crafting_req_priority) + crafting_recipes += recipe + return crafting_recipes //creates every subtype of prototype (excluding prototype) and adds it to list L. //if no list/L is provided, one is created. diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm index 6155c81212b..e1b732c1e35 100644 --- a/code/datums/components/crafting/crafting.dm +++ b/code/datums/components/crafting/crafting.dm @@ -311,6 +311,14 @@ while(Deletion.len) var/DL = Deletion[Deletion.len] Deletion.Cut(Deletion.len) + // Snowflake handling of reagent containers and storage atoms. + // If we consumed them in our crafting, we should dump their contents out before qdeling them. + if(istype(DL, /obj/item/reagent_containers)) + var/obj/item/reagent_containers/container = DL + container.reagents.expose(container.loc, TOUCH) + else if(istype(DL, /obj/item/storage)) + var/obj/item/storage/container = DL + container.emptyStorage() qdel(DL) /datum/component/personal_crafting/proc/component_ui_interact(obj/screen/craft/image, location, control, params, user)