From 0530f2458ae8a5ec56423eebce39a056f627ce6f Mon Sep 17 00:00:00 2001 From: Varlaisvea <125837828+Varlaisvea@users.noreply.github.com> Date: Sun, 28 May 2023 19:55:00 +0100 Subject: [PATCH] fixes infinite morphium duplication exploit (#9046) * fixes very old exploit that we literally just discovered * this is what i get for speedrunning a bugfix * reworks material ejection code * literally it worked fine this is just so github likes it * Update code/game/machinery/autolathe.dm Co-authored-by: Atermonera * Update code/game/machinery/autolathe.dm Co-authored-by: Atermonera * code prettiness --------- Co-authored-by: Atermonera --- code/game/machinery/autolathe.dm | 49 +++++++------------ code/game/machinery/machinery.dm | 14 ++++++ code/game/mecha/mech_fabricator.dm | 23 +-------- code/game/mecha/mech_prosthetics.dm | 23 +-------- .../items/stacks/tiles/fifty_spawner_tiles.dm | 10 ++-- .../objects/items/stacks/tiles/tile_types.dm | 15 +----- code/modules/materials/fifty_spawner_mats.dm | 4 ++ .../materials/materials/organic/grass.dm | 7 +-- code/modules/materials/sheets/organic/wood.dm | 5 ++ code/modules/research/protolathe.dm | 32 +----------- code/modules/research/rdmachines.dm | 2 +- 11 files changed, 58 insertions(+), 126 deletions(-) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 2b4add5ea7..51e76df29d 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -12,7 +12,7 @@ circuit = /obj/item/circuitboard/autolathe var/datum/category_collection/autolathe/machine_recipes - var/list/stored_material = list(MAT_STEEL = 0, MAT_GLASS = 0, MAT_PLASTEEL = 0, MAT_PLASTIC = 0) + materials = list(MAT_STEEL = 0, MAT_GLASS = 0, MAT_PLASTEEL = 0, MAT_PLASTIC = 0) var/list/storage_capacity = list(MAT_STEEL = 0, MAT_GLASS = 0, MAT_PLASTEEL = 0, MAT_PLASTIC = 0) var/datum/category_group/autolathe/current_category @@ -37,10 +37,10 @@ wires = new(src) for(var/Name in name_to_material) - if(Name in stored_material) + if(Name in materials) continue - stored_material[Name] = 0 + materials[Name] = 0 storage_capacity[Name] = 0 soundloop = new(list(src), FALSE) @@ -77,12 +77,12 @@ var/list/material_top = list("") var/list/material_bottom = list("") - for(var/material in stored_material) + for(var/material in materials) if(material != MAT_STEEL && material != MAT_GLASS) // Don't show the Extras unless people care enough to put them in. - if(stored_material[material] <= 0) + if(materials[material] <= 0) continue material_top += "[material]" - material_bottom += "[stored_material[material]]/[storage_capacity[material]]" + material_bottom += "[materials[material]]/[storage_capacity[material]]" dat += "[material_top.Join()][material_bottom.Join()]
" dat += "Filter: [filtertext ? filtertext : "None Set"]
" @@ -107,10 +107,10 @@ //Make sure it's buildable and list requires resources. for(var/material in R.resources) var/coeff = (R.no_scale ? 1 : mat_efficiency) //stacks are unaffected by production coefficient - var/sheets = round(stored_material[material]/round(R.resources[material]*coeff)) + var/sheets = round(materials[material]/(R.resources[material]*coeff)) if(isnull(max_sheets) || max_sheets > sheets) max_sheets = sheets - if(!isnull(stored_material[material]) && stored_material[material] < round(R.resources[material]*coeff)) + if(sheets < 1) can_make = 0 if(!comma) comma = 1 @@ -203,21 +203,21 @@ matter_inputs = eating.matter for(var/material in matter_inputs) - if(isnull(stored_material[material]) || isnull(storage_capacity[material])) + if(isnull(materials[material]) || isnull(storage_capacity[material])) continue - if(stored_material[material] >= storage_capacity[material]) + if(materials[material] >= storage_capacity[material]) continue var/total_material = matter_inputs[material] //If it's a stack, we eat multiple sheets. if(istype(eating,/obj/item/stack)) var/obj/item/stack/stack = eating total_material *= stack.get_amount() - if(stored_material[material] + total_material > storage_capacity[material]) - total_material = storage_capacity[material] - stored_material[material] + if(materials[material] + total_material > storage_capacity[material]) + total_material = storage_capacity[material] - materials[material] filltype = 1 else filltype = 2 - stored_material[material] += total_material + materials[material] += total_material total_used += total_material mass_per_sheet += matter_inputs[material] if(!filltype) @@ -286,14 +286,12 @@ //Check if we still have the materials. var/coeff = (making.no_scale ? 1 : mat_efficiency) //stacks are unaffected by production coefficient for(var/material in making.resources) - if(!isnull(stored_material[material])) - if(stored_material[material] < round(making.resources[material] * coeff) * multiplier) - return + if(isnull(materials[material]) || materials[material] < round(making.resources[material] * coeff) * multiplier) + return //Consume materials. for(var/material in making.resources) - if(!isnull(stored_material[material])) - stored_material[material] = max(0, stored_material[material] - round(making.resources[material] * coeff) * multiplier) + materials[material] = max(0, materials[material] - round(making.resources[material] * coeff) * multiplier) update_icon() // So lid closes @@ -368,16 +366,5 @@ mat_efficiency = 1.1 - man_rating * 0.1// Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.6. Maximum rating of parts is 5 /obj/machinery/autolathe/dismantle() - if(LAZYLEN(stored_material)) - for(var/mat in stored_material) - var/datum/material/M = get_material_by_name(mat) - if(!istype(M)) - continue - if(stored_material[mat] == 0) //Maybe don't try and make null mats... - continue - var/obj/item/stack/material/S = new M.stack_type(get_turf(src)) - if(stored_material[mat] >= S.perunit) - S.amount = round(stored_material[mat] / S.perunit) - else - qdel(S) //Prevents stacks smaller than 1 - return ..() \ No newline at end of file + eject_materials() //obj/machinery proc, in machinery/machinery.dm + ..() \ No newline at end of file diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 268692ce8d..a7ca3385ce 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -111,6 +111,7 @@ Class Procs: var/clickvol = 40 // volume var/interact_offline = 0 // Can the machine be interacted with while de-powered. var/obj/item/circuitboard/circuit = null + var/list/materials = list() //Exclusively used for machines that take materials - lathes, fabricators etc. Honestly overdue for a whole lathe/fab refactor at some point. var/speed_process = FALSE //If false, SSmachines. If true, SSfastprocess. @@ -473,3 +474,16 @@ Class Procs: /datum/proc/remove_visual(mob/M) return + +/obj/machinery/proc/eject_materials() //Used for autolathe, protolathe, mechfab, exofab. Stuff that takes materials, basically. + if(LAZYLEN(materials)) + for(var/mat in materials) + var/datum/material/M = get_material_by_name(mat) + if(!istype(M) || materials[mat] == 0) + continue + var/obj/item/stack/material/S = new M.stack_type(get_turf(src)) + if(materials[mat] >= S.perunit) + S.amount = round(materials[mat] / S.perunit) + else + qdel(S) //Prevents stacks smaller than 1 + return \ No newline at end of file diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index d78782759a..3867b9afdb 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -13,7 +13,7 @@ var/speed = 1 var/mat_efficiency = 1 - var/list/materials = list(MAT_STEEL = 0, "glass" = 0, "plastic" = 0, MAT_GRAPHITE = 0, MAT_PLASTEEL = 0, "gold" = 0, "silver" = 0, MAT_LEAD = 0, "osmium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, "phoron" = 0, "uranium" = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0) + materials = list(MAT_STEEL = 0, "glass" = 0, "plastic" = 0, MAT_GRAPHITE = 0, MAT_PLASTEEL = 0, "gold" = 0, "silver" = 0, MAT_LEAD = 0, "osmium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, "phoron" = 0, "uranium" = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0, MAT_METALHYDROGEN = 0, MAT_SUPERMATTER = 0) var/list/hidden_materials = list(MAT_PLASTEEL, MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM, MAT_METALHYDROGEN, MAT_SUPERMATTER) var/res_max_amount = 200000 @@ -70,8 +70,7 @@ add_overlay("mechfab-active") /obj/machinery/mecha_part_fabricator/dismantle() - for(var/f in materials) - eject_materials(f, -1) + eject_materials() //Proc on obj/machinery in code/game/machinery/machinery.dm ..() /obj/machinery/mecha_part_fabricator/RefreshParts() @@ -290,24 +289,6 @@ if(!hidden_mat) . += list(list("mat" = capitalize(T), "amt" = materials[T])) -/obj/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything - var/recursive = amount == -1 ? 1 : 0 - var/matstring = lowertext(material) - var/datum/material/M = get_material_by_name(matstring) - - var/obj/item/stack/material/S = M.place_sheet(get_turf(src)) - if(amount <= 0) - amount = S.max_amount - var/ejected = min(round(materials[matstring] / S.perunit), amount) - S.amount = min(ejected, amount) - if(S.amount <= 0) - qdel(S) - return - materials[matstring] -= ejected * S.perunit - if(recursive && materials[matstring] >= S.perunit) - eject_materials(matstring, -1) - update_busy() - /obj/machinery/mecha_part_fabricator/proc/sync() sync_message = "Error: no console found." for(var/obj/machinery/computer/rdconsole/RDC in get_area_all_atoms(get_area(src))) diff --git a/code/game/mecha/mech_prosthetics.dm b/code/game/mecha/mech_prosthetics.dm index 5afb33d7c3..b6fe20b9aa 100644 --- a/code/game/mecha/mech_prosthetics.dm +++ b/code/game/mecha/mech_prosthetics.dm @@ -13,7 +13,7 @@ var/speed = 1 var/mat_efficiency = 1 - var/list/materials = list(MAT_STEEL = 0, "glass" = 0, "plastic" = 0, MAT_GRAPHITE = 0, MAT_PLASTEEL = 0, "gold" = 0, "silver" = 0, MAT_LEAD = 0, "osmium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, "phoron" = 0, "uranium" = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0) + materials = list(MAT_STEEL = 0, "glass" = 0, "plastic" = 0, MAT_GRAPHITE = 0, MAT_PLASTEEL = 0, "gold" = 0, "silver" = 0, MAT_LEAD = 0, "osmium" = 0, "diamond" = 0, MAT_DURASTEEL = 0, "phoron" = 0, "uranium" = 0, MAT_VERDANTIUM = 0, MAT_MORPHIUM = 0) var/list/hidden_materials = list(MAT_DURASTEEL, MAT_GRAPHITE, MAT_VERDANTIUM, MAT_MORPHIUM) var/res_max_amount = 200000 @@ -66,8 +66,7 @@ icon_state = "[icon_state]_work" /obj/machinery/pros_fabricator/dismantle() - for(var/f in materials) - eject_materials(f, -1) + eject_materials() //Proc on obj/machinery in code/game/machinery/machinery.dm ..() /obj/machinery/pros_fabricator/RefreshParts() @@ -328,24 +327,6 @@ if(!hidden_mat) . += list(list("mat" = capitalize(T), "amt" = materials[T])) -/obj/machinery/pros_fabricator/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything - var/recursive = amount == -1 ? 1 : 0 - var/matstring = lowertext(material) - var/datum/material/M = get_material_by_name(matstring) - - var/obj/item/stack/material/S = M.place_sheet(get_turf(src)) - if(amount <= 0) - amount = S.max_amount - var/ejected = min(round(materials[matstring] / S.perunit), amount) - S.amount = min(ejected, amount) - if(S.amount <= 0) - qdel(S) - return - materials[matstring] -= ejected * S.perunit - if(recursive && materials[matstring] >= S.perunit) - eject_materials(matstring, -1) - update_busy() - /obj/machinery/pros_fabricator/proc/sync() sync_message = "Error: no console found." for(var/obj/machinery/computer/rdconsole/RDC in get_area_all_atoms(get_area(src))) diff --git a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm index 6e805411a4..1c2839934e 100644 --- a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm +++ b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm @@ -1,22 +1,22 @@ //see /code/modules/materials/fifty_stacks.dm for how this stuff works -/obj/fiftyspawner/grass +/obj/fiftyspawner/grasstiles name = "stack of grass" type_to_spawn = /obj/item/stack/tile/grass -/obj/fiftyspawner/grass/sif +/obj/fiftyspawner/grasstiles/sif name = "stack of sifgrass" type_to_spawn = /obj/item/stack/tile/grass/sif -/obj/fiftyspawner/grass/sif/forest +/obj/fiftyspawner/grasstiles/sif/forest name = "stack of sifgrass" type_to_spawn = /obj/item/stack/tile/grass/sif/forest -/obj/fiftyspawner/wood +/obj/fiftyspawner/woodtiles name = "stack of wood" type_to_spawn = /obj/item/stack/tile/wood -/obj/fiftyspawner/wood/sif +/obj/fiftyspawner/woodtiles/sif name = "stack of alien wood" type_to_spawn = /obj/item/stack/tile/wood/sif diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index a0b7528edf..099a1d8453 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -20,25 +20,14 @@ drop_sound = 'sound/items/drop/axe.ogg' pickup_sound = 'sound/items/pickup/axe.ogg' -//crafting / welding vars - var/datum/material/material //*sigh* i guess this is how we're doing this. - var/craftable = FALSE //set to TRUE for tiles you can craft stuff from directly, like grass +//welding vars var/can_weld = FALSE //set to TRUE for tiles you can reforge into their components via welding, like metal var/welds_into = /obj/item/stack/material/steel //what you get from the welding. defaults to steel. - var/default_type = DEFAULT_WALL_MATERIAL - /obj/item/stack/tile/Initialize() . = ..() randpixel_xy() - if(craftable) - material = get_material_by_name("[default_type]") - if(!material) - return INITIALIZE_HINT_QDEL - if(material) //sanity check - recipes = material.get_recipes() - stacktype = material.stack_type /obj/item/stack/tile/attackby(obj/item/W as obj, mob/user as mob) if (istype(W, /obj/item/weldingtool)) @@ -73,7 +62,6 @@ singular_name = "grass floor tile" desc = "A patch of grass like they often use on golf courses." icon_state = "tile_grass" - default_type = "grass" force = 1.0 throwforce = 1.0 throw_speed = 5 @@ -83,7 +71,6 @@ no_variants = FALSE drop_sound = 'sound/items/drop/herb.ogg' pickup_sound = 'sound/items/pickup/herb.ogg' - craftable = TRUE /obj/item/stack/tile/grass/sif name = "sivian grass tile" diff --git a/code/modules/materials/fifty_spawner_mats.dm b/code/modules/materials/fifty_spawner_mats.dm index 1018b5d972..58a9d95f08 100644 --- a/code/modules/materials/fifty_spawner_mats.dm +++ b/code/modules/materials/fifty_spawner_mats.dm @@ -92,6 +92,10 @@ name = "stack of durasteel hull" type_to_spawn = /obj/item/stack/material/durasteel/hull +/obj/fiftyspawner/grass + name = "stack of grass" + type_to_spawn = /obj/item/stack/material/grass + /obj/fiftyspawner/wood name = "stack of wood" type_to_spawn = /obj/item/stack/material/wood diff --git a/code/modules/materials/materials/organic/grass.dm b/code/modules/materials/materials/organic/grass.dm index 4f2af4541e..a0356e24aa 100644 --- a/code/modules/materials/materials/organic/grass.dm +++ b/code/modules/materials/materials/organic/grass.dm @@ -1,7 +1,7 @@ /datum/material/grass - name = MAT_GRASS + name = "grass" display_name = "grass" - stack_type = /obj/item/stack/tile/grass + stack_type = /obj/item/stack/material/grass ignition_point = T0C+300 melting_point = T0C+300 protectiveness = 0 @@ -27,5 +27,6 @@ new /datum/stack_recipe("pink-and-purple flowers", /obj/structure/flora/ausbushes/ppflowers, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), new /datum/stack_recipe("sparse grass", /obj/structure/flora/ausbushes/sparsegrass, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), new /datum/stack_recipe("full grass", /obj/structure/flora/ausbushes/fullgrass, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]") - )) + )), + new /datum/stack_recipe("grass floor tile", /obj/item/stack/tile/grass, 1, 4, 20, pass_stack_color = TRUE, recycle_material = "[name]"), ) \ No newline at end of file diff --git a/code/modules/materials/sheets/organic/wood.dm b/code/modules/materials/sheets/organic/wood.dm index eb95131425..866c5b3c5d 100644 --- a/code/modules/materials/sheets/organic/wood.dm +++ b/code/modules/materials/sheets/organic/wood.dm @@ -53,3 +53,8 @@ to_chat(user, "You add the newly-formed wood to the stack. It now contains [existing_wood.amount] planks.") else return ..() + +/obj/item/stack/material/grass + name = "grass" + icon_state = "tile_grass" + default_type = "grass" \ No newline at end of file diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 7bccd86044..de51f73c6c 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -81,11 +81,9 @@ speed = T / 2 /obj/machinery/r_n_d/protolathe/dismantle() - for(var/f in materials) - eject_materials(f, -1) + eject_materials() //Proc on obj/machinery in code/game/machinery/machinery.dm ..() - /obj/machinery/r_n_d/protolathe/update_icon() cut_overlays() @@ -211,30 +209,4 @@ if(mat_efficiency != 1) // No matter out of nowhere if(new_item.matter && new_item.matter.len > 0) for(var/i in new_item.matter) - new_item.matter[i] = new_item.matter[i] * mat_efficiency - -/obj/machinery/r_n_d/protolathe/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything - var/recursive = amount == -1 ? 1 : 0 - material = lowertext(material) - var/obj/item/stack/material/mattype - var/datum/material/MAT = get_material_by_name(material) - - if(!MAT) - return - - mattype = MAT.stack_type - - if(!mattype) - return - - var/obj/item/stack/material/S = new mattype(loc) - if(amount <= 0) - amount = S.max_amount - var/ejected = min(round(materials[material] / S.perunit), amount) - S.amount = min(ejected, amount) - if(S.amount <= 0) - qdel(S) - return - materials[material] -= ejected * S.perunit - if(recursive && materials[material] >= S.perunit) - eject_materials(material, -1) + new_item.matter[i] = new_item.matter[i] * mat_efficiency \ No newline at end of file diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm index 7341d1a19c..a70acb9aa7 100644 --- a/code/modules/research/rdmachines.dm +++ b/code/modules/research/rdmachines.dm @@ -11,7 +11,7 @@ var/busy = 0 var/obj/machinery/computer/rdconsole/linked_console - var/list/materials = list() // Materials this machine can accept. + materials = list() // Materials this machine can accept. var/list/hidden_materials = list() // Materials this machine will not display, unless it contains them. Must be in the materials list as well. /obj/machinery/r_n_d/attack_hand(mob/user as mob)