From 55e1b1fe0fb54d92d717da5a2c5d0bb0869230bb Mon Sep 17 00:00:00 2001 From: Ghom <42542238+Ghommie@users.noreply.github.com> Date: Sun, 12 Jul 2026 13:08:50 +0200 Subject: [PATCH] Fixing crafting unit test CI issues by requiring replacements to abstract types to be manually inputed in the code rather than picked randomly on runtime (#96929) --- code/datums/components/crafting/tailoring.dm | 6 ++--- .../datums/components/crafting/weapon_ammo.dm | 1 + .../objects/structures/cannons/cannonballs.dm | 2 +- code/modules/autowiki/pages/soup.dm | 7 ++---- .../recipes/tablecraft/recipes_cake.dm | 1 + .../recipes/tablecraft/recipes_lizard.dm | 1 + .../recipes/tablecraft/recipes_martian.dm | 1 + .../recipes/tablecraft/recipes_meat.dm | 4 ++++ .../recipes/tablecraft/recipes_pizza.dm | 1 + code/modules/hydroponics/grown/mushrooms.dm | 3 --- code/modules/unit_tests/crafting.dm | 23 +++++++++++-------- .../unit_tests/make_vegan_wellington.dm | 8 +++++-- 12 files changed, 34 insertions(+), 24 deletions(-) diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index 8406bfeeefa..569d38ed0a1 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -253,21 +253,21 @@ /datum/crafting_recipe/prisonsuit name = "Prisoner Uniform (Suit)" result = /obj/item/clothing/under/rank/prisoner - reqs = list(/obj/item/stack/sheet/cloth = 3, /obj/item/stack/license_plates = 1) + reqs = list(/obj/item/stack/sheet/cloth = 3, /obj/item/stack/license_plates/filled = 1) time = 2 SECONDS category = CAT_CLOTHING /datum/crafting_recipe/prisonskirt name = "Prisoner Uniform (Skirt)" result = /obj/item/clothing/under/rank/prisoner/skirt - reqs = list(/obj/item/stack/sheet/cloth = 3, /obj/item/stack/license_plates = 1) + reqs = list(/obj/item/stack/sheet/cloth = 3, /obj/item/stack/license_plates/filled = 1) time = 2 SECONDS category = CAT_CLOTHING /datum/crafting_recipe/prisonshoes name = "Orange Prison Shoes" result = /obj/item/clothing/shoes/sneakers/orange - reqs = list(/obj/item/stack/sheet/cloth = 2, /obj/item/stack/license_plates = 1) + reqs = list(/obj/item/stack/sheet/cloth = 2, /obj/item/stack/license_plates/filled = 1) time = 1 SECONDS category = CAT_CLOTHING diff --git a/code/datums/components/crafting/weapon_ammo.dm b/code/datums/components/crafting/weapon_ammo.dm index 0fdb98b23a4..f48a2abcb82 100644 --- a/code/datums/components/crafting/weapon_ammo.dm +++ b/code/datums/components/crafting/weapon_ammo.dm @@ -113,6 +113,7 @@ ) category = CAT_WEAPON_AMMO crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED + unit_test_spawn_extras = list(/obj/item/stack/sheet/iron = 5) //the sheet type is abstract /datum/crafting_recipe/arrow name = "Arrow" diff --git a/code/game/objects/structures/cannons/cannonballs.dm b/code/game/objects/structures/cannons/cannonballs.dm index fca8eb7e901..a9808de5c49 100644 --- a/code/game/objects/structures/cannons/cannonballs.dm +++ b/code/game/objects/structures/cannons/cannonballs.dm @@ -71,7 +71,7 @@ base_icon_state = "trashballs" merge_type = /obj/item/stack/cannonball/trashball projectile_type = /obj/projectile/bullet/cannonball/trashball - custom_materials = list(/datum/material/alloy/plasteel = SHEET_MATERIAL_AMOUNT) + custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5) /obj/item/stack/cannonball/trashball/four amount = 4 diff --git a/code/modules/autowiki/pages/soup.dm b/code/modules/autowiki/pages/soup.dm index 754beb3a82a..d46411e6920 100644 --- a/code/modules/autowiki/pages/soup.dm +++ b/code/modules/autowiki/pages/soup.dm @@ -71,11 +71,8 @@ for(var/obj/item/food_type as anything in soup_recipe.required_ingredients) var/num_needed = soup_recipe.required_ingredients[food_type] - // Instantiating this so we can do plurality correctly. - // We can use initial but it'll give us stuff like "eyballss". - var/obj/item/food = new food_type() - all_needs_text += "[num_needed] [food.name]\s" - qdel(food) + // \s alone doesn't work well on item names along and we don't want "eyeballss" with two s. + all_needs_text += "[num_needed] [food_type::gender == PLURAL ? food_type::name : "[food_type::name]\s"]" all_needs_text += soup_recipe.describe_recipe_details() all_needs_text += "At temperature [soup_recipe.required_temp]K" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm index d2eb09f16cb..cd6c9c9a059 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm @@ -159,6 +159,7 @@ added_foodtypes = GROSS dish_category = DISH_CAKE meal_category = MEAL_DESSERT + unit_test_spawn_extras = list(/obj/item/circuitboard/machine/vendor = 2) //cannot spawn the abstract circuit board /datum/crafting_recipe/food/berry_chocolate_cake name = "strawberry chocolate cake" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm index 8ed7580758e..99fb61c1cff 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_lizard.dm @@ -385,6 +385,7 @@ result = /obj/item/food/pizza/flatbread/mushroom cuisine_category = CUISINE_LIZARD dish_category = DISH_BREAD + unit_test_spawn_extras = list(/obj/item/food/grown/mushroom/chanterelle = 3) //generic mushrooms /datum/crafting_recipe/food/nutty_flatbread name = "Nut paste flatbread" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm index ac5699481b1..d4ca73d3dee 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_martian.dm @@ -204,6 +204,7 @@ removed_foodtypes = RAW|BREAKFAST cuisine_category = CUISINE_MARTIAN dish_category = DISH_RICE + unit_test_spawn_extras = list(/obj/item/food/grown/mushroom/chanterelle = 1) //generic mushrooms /datum/crafting_recipe/food/bulgogi_noodles name = "Bulgogi noodles" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm index 4cb84004435..ab60a0f5adf 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_meat.dm @@ -256,6 +256,7 @@ result = /obj/item/food/beef_stroganoff added_foodtypes = DAIRY dish_category = DISH_MEAT + unit_test_spawn_extras = list(/obj/item/food/grown/mushroom/chanterelle = 2) //generic mushrooms /datum/crafting_recipe/food/beef_wellington name = "Beef Wellington" @@ -272,6 +273,7 @@ result = /obj/item/food/beef_wellington removed_foodtypes = BREAKFAST dish_category = DISH_MEAT + unit_test_spawn_extras = list(/obj/item/food/grown/mushroom/chanterelle = 1) //generic mushrooms /datum/crafting_recipe/food/korta_wellington name = "Korta Wellington" @@ -288,6 +290,7 @@ result = /obj/item/food/korta_wellington removed_foodtypes = BREAKFAST dish_category = DISH_MEAT + unit_test_spawn_extras = list(/obj/item/food/grown/mushroom/chanterelle = 1) //generic mushrooms /datum/crafting_recipe/food/full_roast name = "Roast Chicken Dinner" @@ -360,6 +363,7 @@ ) result = /obj/item/food/full_english dish_category = DISH_MEAT + unit_test_spawn_extras = list(/obj/item/food/grown/mushroom/chanterelle = 1) //generic mushrooms /datum/crafting_recipe/food/envirochow name = "Envirochow" diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pizza.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pizza.dm index 0f807e47171..be0c994556e 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pizza.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pizza.dm @@ -42,6 +42,7 @@ /obj/item/food/cheese/wedge = 1, ) result = /obj/item/food/pizza/mushroom/raw + unit_test_spawn_extras = list(/obj/item/food/grown/mushroom/chanterelle = 5) //generic mushrooms /datum/crafting_recipe/food/pizza/vegetable reqs = list( diff --git a/code/modules/hydroponics/grown/mushrooms.dm b/code/modules/hydroponics/grown/mushrooms.dm index 7a1003ed2ad..d465e4dad90 100644 --- a/code/modules/hydroponics/grown/mushrooms.dm +++ b/code/modules/hydroponics/grown/mushrooms.dm @@ -1,9 +1,6 @@ /obj/item/food/grown/mushroom name = "mushroom" abstract_type = /obj/item/food/grown/mushroom - // This is a prototype that should never be spawned - // but we'll default it to SOME seed if it does end up spawning just so we don't runtime horribly - seed = /obj/item/seeds/chanter bite_consumption_mod = 3 foodtypes = VEGETABLES wine_power = 40 diff --git a/code/modules/unit_tests/crafting.dm b/code/modules/unit_tests/crafting.dm index 8e152e17c09..9a6a9a29a4a 100644 --- a/code/modules/unit_tests/crafting.dm +++ b/code/modules/unit_tests/crafting.dm @@ -65,18 +65,19 @@ LAZYADD(uncreatables_found, req_path) continue + // A recipe might accept an abstract base type as its reqs - e.g. obj/item/food/grown - signifying it can use any item of that type. + // However, we cannot create those abstract base types... but we also cannot pick a random subtype everytime either, + // as sutypes can have different custom_materials between them, so doing that will lead us to sporiadic errors. + // The safest course of action is to make the contributor pick a valid subtype (as generic as possible. please) to use in its place. + var/datum/req_path_datum = req_path + if(req_path_datum.abstract_type == req_path) + LAZYADD(uncreatables_found, req_path) + continue + if(ispath(req_path, /obj/item/stack)) //it's a stack new req_path(turf, /*new_amount =*/ amount, /*merge =*/ FALSE) continue - // Some recipes might accept an abstract base type as its reqs - e.g. obj/item/food/grown - signifying it can use any item of that type. - // Let's not actually create those abstract base types though, and instead pick a random subtype to use. - var/datum/req_path_datum = req_path - if(req_path_datum.abstract_type == req_path) - var/list/subtypes = valid_subtypesof(req_path_datum) - if(length(subtypes)) - req_path = pick(subtypes) - //it's any other item for(var/iteration in 1 to amount) new req_path(turf) @@ -122,9 +123,11 @@ tool.moveToNullspace() if(istext(result) || isnull(result)) //construct_item() returned a text string telling us why it failed. - TEST_FAIL("[recipe.type] couldn't be crafted during unit test[result || ", result is null for some reason!"]") if(uncreatables_found) - TEST_FAIL("The following objects that shouldn't be instantiated during unit tests were found in [recipe]: [english_list(uncreatables_found)]") + TEST_FAIL("Abstract types found in the requirements of [recipe.type]: [english_list(uncreatables_found)]. \ + Use the unit_test_spawn_extras list var of the recipe to spawn non-abstract subtypes instead.") + else + TEST_FAIL("[recipe.type] couldn't be crafted during unit test[result || ", result is null for some reason!"]") clear_trash() return //enforcing materials parity between crafted and spawned for turfs would be more trouble than worth here diff --git a/code/modules/unit_tests/make_vegan_wellington.dm b/code/modules/unit_tests/make_vegan_wellington.dm index 6092018f4d5..8b497ff2058 100644 --- a/code/modules/unit_tests/make_vegan_wellington.dm +++ b/code/modules/unit_tests/make_vegan_wellington.dm @@ -18,8 +18,12 @@ var/datum/crafting_recipe/food/beef_wellington/recipe = locate() in GLOB.cooking_recipes // bake_a_cake should already check that batters and doughes can be made, so let's not waste time making the dough from scratch - for(var/ingredient in recipe.reqs) - var/amount = recipe.reqs[ingredient] + var/list/to_spawn = recipe.reqs | recipe.unit_test_spawn_extras + for(var/ingredient in to_spawn) + var/datum/ingredient_path = ingredient + if(ingredient_path::abstract_type == ingredient_path) //skip abstract types + continue + var/amount = to_spawn[ingredient] if(ispath(ingredient, /datum/reagent)) beaker.reagents.add_reagent(ingredient, amount) else if(ispath(ingredient, /obj/item/food/meat)) //we will use vegetable variants for this