General code maintenance for Mat container related stuff (#77671)

1. Removes `/obj/machinery/ore_silo/proc/remote_attackby()`. This proc
calls `datum/component/material_container/user_insert()` anyway which
performs all the checks necessary for inserting stuff into the ore silo
and `/obj/machinery/ore_silo/proc/remote_attackby()` was just repeating
its code & checks. So now inserting into the ore silo is directly
handled by the mat container without this proxy proc making the
operation slightly faster
2. Removed silo `attackby` code. Same operations can be done via
`screwdriver_act` & `crowbar_act` procs much cleaner
3. The ore silo now hooks onto signals
`COMSIG_MATCONTAINER_ITEM_CONSUMED` and
`COMSIG_MATCONTAINER_SHEETS_RETRIVED` and logs into silo when they are
triggered. This means when you insert/eject sheets from the silo the
connected machine performing the operation no longer has to do the
logging manually thus the proc `silo_log` has been removed from a lot of
places ,reducing overall code size
4. A lot of stuff that use materials from the ore silo follow this
pattern.

i.e. They first use the materials from the silo and then log it via
`silo_log` proc. This code pattern is repeated in a lot of places so
let's just merge these 2 lines with some extra sanity checks into a
single proc inside `remote_materials` itself. That's what was done and
the number of places where you log manually into the silo has been
removed further reducing code size everywhere.
5. Added auto doc & cleaned up some procs

Since logging is now done by the ore silo directly, we need a way to
pass the machine that is inserting items into the silo to the signal
handlers of the ore silo [via the `context` var]. So other code changes
elsewhere is because of this var
This commit is contained in:
SyncIt21
2023-08-21 22:23:01 +00:00
committed by GitHub
parent d181bc3c9e
commit 9aed3b6a8f
14 changed files with 178 additions and 162 deletions
@@ -131,19 +131,27 @@
* - [source][/obj/item]: The source of the materials we are inserting.
* - multiplier: The multiplier for the materials extract from this item being inserted.
* - breakdown_flags: The breakdown bitflags that will be used to retrieve the materials from the source
* - context: the atom performing the operation, this is the last argument sent in COMSIG_MATCONTAINER_ITEM_CONSUMED and is used mostly for silo logging
*/
/datum/component/material_container/proc/insert_item_materials(obj/item/source, multiplier = 1, breakdown_flags = mat_container_flags)
/datum/component/material_container/proc/insert_item_materials(obj/item/source, multiplier = 1, breakdown_flags = mat_container_flags, atom/context = parent)
var/primary_mat
var/max_mat_value = 0
var/material_amount = 0
var/list/item_materials = source.get_material_composition(breakdown_flags)
var/list/mats_consumed = list()
for(var/MAT in item_materials)
if(!can_hold_material(MAT))
continue
materials[MAT] += OPTIMAL_COST(item_materials[MAT] * multiplier)
var/mat_amount = OPTIMAL_COST(item_materials[MAT] * multiplier)
materials[MAT] += mat_amount
if(item_materials[MAT] > max_mat_value)
max_mat_value = item_materials[MAT]
primary_mat = MAT
mats_consumed[MAT] = mat_amount
material_amount += mat_amount
if(length(mats_consumed))
SEND_SIGNAL(src, COMSIG_MATCONTAINER_ITEM_CONSUMED, source, primary_mat, mats_consumed, material_amount, context)
return primary_mat
//===================================================================================
@@ -188,15 +196,16 @@
* - [weapon][obj/item]: the item you are trying to insert
* - multiplier: The multiplier for the materials being inserted
* - breakdown_flags: The breakdown bitflags that will be used to retrieve the materials from the source
* - context: the atom performing the operation, this is the last argument sent in COMSIG_MATCONTAINER_ITEM_CONSUMED and is used mostly for silo logging
*/
/datum/component/material_container/proc/insert_item(obj/item/weapon, multiplier = 1, breakdown_flags = mat_container_flags)
/datum/component/material_container/proc/insert_item(obj/item/weapon, multiplier = 1, breakdown_flags = mat_container_flags, atom/context = parent)
if(QDELETED(weapon))
return MATERIAL_INSERT_ITEM_NO_MATS
multiplier = CEILING(multiplier, 0.01)
var/obj/item/target = weapon
var/material_amount = get_item_material_amount(target, breakdown_flags) * multiplier
var/material_amount = OPTIMAL_COST(get_item_material_amount(target, breakdown_flags) * multiplier)
if(!material_amount)
return MATERIAL_INSERT_ITEM_NO_MATS
var/obj/item/stack/item_stack
@@ -218,9 +227,8 @@
return MATERIAL_INSERT_ITEM_NO_SPACE
//do the insert
var/last_inserted_id = insert_item_materials(target, multiplier, breakdown_flags)
var/last_inserted_id = insert_item_materials(target, multiplier, breakdown_flags, context)
if(!isnull(last_inserted_id))
SEND_SIGNAL(src, COMSIG_MATCONTAINER_ITEM_CONSUMED, target, last_inserted_id, material_amount, src)
qdel(target) //item gone
return material_amount
else if(!isnull(item_stack) && item_stack != target) //insertion failed, merge the split stack back into the original
@@ -242,8 +250,9 @@
* * held_item - the item to insert
* * user - the mob inserting this item
* * breakdown_flags - how this item and all it's contents inside are broken down during insertion. This is unique to the machine doing the insertion
* * context - the atom performing the operation, this is the last argument sent in COMSIG_MATCONTAINER_ITEM_CONSUMED and is used mostly for silo logging
*/
/datum/component/material_container/proc/user_insert(obj/item/held_item, mob/living/user, breakdown_flags = mat_container_flags)
/datum/component/material_container/proc/user_insert(obj/item/held_item, mob/living/user, breakdown_flags = mat_container_flags, atom/context = parent)
set waitfor = FALSE
. = 0
@@ -327,7 +336,7 @@
//insert the item
var/item_name = target.name
var/inserted = insert_item(target, breakdown_flags = mat_container_flags)
var/inserted = insert_item(target, 1, mat_container_flags, context)
if(inserted > 0)
. += inserted
inserted /= SHEET_MATERIAL_AMOUNT // display units inserted as sheets for improved readability
@@ -564,44 +573,52 @@
* sheet_amt: number of sheets to extract
* [material][datum/material]: type of sheets present in this container to extract
* [target][atom]: drop location
* [atom][context]: context - the atom performing the operation, this is the last argument sent in COMSIG_MATCONTAINER_SHEETS_RETRIVED and is used mostly for silo logging
*/
/datum/component/material_container/proc/retrieve_sheets(sheet_amt, datum/material/material, atom/target = null)
/datum/component/material_container/proc/retrieve_sheets(sheet_amt, datum/material/material, atom/target = null, atom/context = parent)
//do we support sheets of this material
if(!material.sheet_type)
return 0 //Add greyscale sheet handling here later
if(sheet_amt <= 0)
if(!can_hold_material(material))
return 0
//requested amount greater than available amount or just an invalid value
sheet_amt = min(round(materials[material] / SHEET_MATERIAL_AMOUNT), sheet_amt)
if(sheet_amt <= 0)
return 0
//auto drop location
if(!target)
var/atom/parent_atom = parent
target = parent_atom.drop_location()
if(materials[material] < (sheet_amt * SHEET_MATERIAL_AMOUNT))
sheet_amt = round(materials[material] / SHEET_MATERIAL_AMOUNT)
var/count = 0
while(sheet_amt > MAX_STACK_SIZE)
var/obj/item/stack/sheet/new_sheets = new material.sheet_type(target, MAX_STACK_SIZE, null, list((material) = SHEET_MATERIAL_AMOUNT))
count += MAX_STACK_SIZE
use_amount_mat(sheet_amt * SHEET_MATERIAL_AMOUNT, material)
sheet_amt -= MAX_STACK_SIZE
SEND_SIGNAL(src, COMSIG_MATCONTAINER_SHEETS_RETRIVED, new_sheets)
if(sheet_amt >= 1)
var/obj/item/stack/sheet/new_sheets = new material.sheet_type(target, sheet_amt, null, list((material) = SHEET_MATERIAL_AMOUNT))
count += sheet_amt
use_amount_mat(sheet_amt * SHEET_MATERIAL_AMOUNT, material)
SEND_SIGNAL(src, COMSIG_MATCONTAINER_SHEETS_RETRIVED, new_sheets)
return count
if(!target)
return 0
//eject sheets based on available amount after each iteration
var/count = 0
while(sheet_amt > 0)
//create sheets in null space so it doesn't merge & delete itself
var/obj/item/stack/sheet/new_sheets = new material.sheet_type(null, min(sheet_amt, MAX_STACK_SIZE), null, list((material) = SHEET_MATERIAL_AMOUNT))
count += new_sheets.amount
//use material & deduct work needed
use_amount_mat(new_sheets.amount * SHEET_MATERIAL_AMOUNT, material)
sheet_amt -= new_sheets.amount
//send signal
SEND_SIGNAL(src, COMSIG_MATCONTAINER_SHEETS_RETRIVED, new_sheets, context)
//now move to target so it gets merged
new_sheets.forceMove(target)
return count
/**
* Proc to get all the materials and dump them as sheets
*
* Arguments:
* - target: drop location of the sheets
* - context: the atom which is ejecting the sheets. Used mostly in silo logging
*/
/datum/component/material_container/proc/retrieve_all(target = null)
/datum/component/material_container/proc/retrieve_all(target = null, atom/context = parent)
var/result = 0
for(var/MAT in materials)
var/amount = materials[MAT]
result += retrieve_sheets(amount2sheet(amount), MAT, target)
result += retrieve_sheets(amount2sheet(materials[MAT]), MAT, target, context)
return result
//============================================================================================
@@ -22,13 +22,6 @@ handles linking back and forth.
///Flags used when converting inserted materials into their component materials.
var/mat_container_flags = NONE
//Internal vars
///Prepare storage when component is registered to parent. This allows local material container(if created) to be first in the component list so it gets GC'd properly
var/_prepare_on_register = FALSE
///Are we trying to to connect to remote ore silo or not
var/_connect_to_silo = FALSE
/datum/component/remote_materials/Initialize(mapload, allow_standalone = TRUE, force_connect = FALSE, mat_container_flags = NONE)
if (!isatom(parent))
return COMPONENT_INCOMPATIBLE
@@ -36,23 +29,26 @@ handles linking back and forth.
src.allow_standalone = allow_standalone
src.mat_container_flags = mat_container_flags
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(OnAttackBy))
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(OnMultitool))
var/turf/T = get_turf(parent)
_connect_to_silo = FALSE
var/connect_to_silo = FALSE
if(force_connect || (mapload && is_station_level(T.z)))
_connect_to_silo = TRUE
connect_to_silo = TRUE
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, TYPE_PROC_REF(/datum/component/remote_materials, SiloAttackBy))
if(mapload) // wait for silo to initialize during mapload
addtimer(CALLBACK(src, PROC_REF(_PrepareStorage), _connect_to_silo))
addtimer(CALLBACK(src, PROC_REF(_PrepareStorage), connect_to_silo))
else //directly register in round
_prepare_on_register = TRUE
/datum/component/remote_materials/RegisterWithParent()
if(_prepare_on_register)
_PrepareStorage(_connect_to_silo)
_PrepareStorage(connect_to_silo)
/**
* Internal proc. prepares local storage if onnect_to_silo = FALSE
*
* Arguments
* connect_to_silo- if true connect to global silo. If not successfull then go to local storage
* only if allow_standalone = TRUE, else you a null mat_container
*/
/datum/component/remote_materials/proc/_PrepareStorage(connect_to_silo)
if (connect_to_silo)
silo = GLOB.ore_silo_default
@@ -112,7 +108,12 @@ handles linking back and forth.
if (!silo && mat_container)
mat_container.max_amount = size
// called if disconnected by ore silo UI or destruction
/**
* Disconnect this component from the remote silo
*
* Arguments
* old_silo- The silo we are trying to disconnect from
*/
/datum/component/remote_materials/proc/disconnect_from(obj/machinery/ore_silo/old_silo)
if (!old_silo || silo != old_silo)
return
@@ -122,12 +123,14 @@ handles linking back and forth.
if (allow_standalone)
_MakeLocal()
/datum/component/remote_materials/proc/OnAttackBy(datum/source, obj/item/I, mob/user)
///Insert mats into silo
/datum/component/remote_materials/proc/SiloAttackBy(datum/source, obj/item/target, mob/user)
SIGNAL_HANDLER
if (silo && isstack(I))
if (silo.remote_attackby(parent, user, I, mat_container_flags))
return COMPONENT_NO_AFTERATTACK
if(silo)
mat_container.user_insert(target, user, mat_container_flags, parent)
return COMPONENT_NO_AFTERATTACK
/datum/component/remote_materials/proc/OnMultitool(datum/source, mob/user, obj/item/I)
SIGNAL_HANDLER
@@ -152,52 +155,87 @@ handles linking back and forth.
silo.ore_connected_machines += src
silo.updateUsrDialog()
mat_container = silo.GetComponent(/datum/component/material_container)
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, TYPE_PROC_REF(/datum/component/remote_materials, SiloAttackBy))
to_chat(user, span_notice("You connect [parent] to [silo] from the multitool's buffer."))
return COMPONENT_BLOCK_TOOL_ATTACK
/datum/component/remote_materials/proc/check_z_level(obj/silo_to_check)
SIGNAL_HANDLER
if(!silo_to_check)
if(isnull(silo))
return FALSE
silo_to_check = silo
/**
* Checks if the param silo is in the same level as this components parent i.e. connected machine, rcd, etc
*
* Arguments
* silo_to_check- Is this components parent in the same Z level as this param silo. If null
* then check this components connected silo
*
* Returns true if both are on the station or same z level
*/
/datum/component/remote_materials/proc/check_z_level(obj/silo_to_check = silo)
if(isnull(silo_to_check))
return FALSE
var/turf/current_turf = get_turf(parent)
var/turf/silo_turf = get_turf(silo_to_check)
if(!is_valid_z_level(silo_turf, current_turf))
return is_valid_z_level(get_turf(silo_to_check), get_turf(parent))
/// returns TRUE if this connection put on hold by the silo
/datum/component/remote_materials/proc/on_hold()
return check_z_level() ? silo.holds[src] : FALSE
/**
* Internal proc to check if this connection can use any materials from the silo
* Returns true only if
* - The parent is of type movable atom
* - A mat container is actually present
* - The silo in not on hold
*/
/datum/component/remote_materials/proc/_can_use_resource()
var/atom/movable/movable_parent = parent
if (!istype(movable_parent))
return FALSE
if (!mat_container) //no silolink & local storage not supported
movable_parent.say("No access to material storage, please contact the quartermaster.")
return FALSE
if(on_hold()) //silo on hold
movable_parent.say("Mineral access is on hold, please contact the quartermaster.")
return FALSE
return TRUE
/datum/component/remote_materials/proc/on_hold()
if(!check_z_level())
return FALSE
return silo.holds[src]
/**
* Use materials from either the silo(if connected) or from the local storage. If silo then this action
* is logged else not e.g. action="build" & name="matter bin" means you are trying to build an matter bin
*
* Arguments
* [mats][list]- list of materials to use
* coefficient- each mat unit is scaled by this value then rounded. This value if usually your machine efficiency e.g. upgraded protolathe has reduced costs
* multiplier- each mat unit is scaled by this value then rounded after it is scaled by coefficient. This value is your print quatity e.g. printing multiple items
* action- For logging only. e.g. build, create, i.e. the action you are trying to perform
* name- For logging only. the design you are trying to build e.g. matter bin, etc.
*/
/datum/component/remote_materials/proc/use_materials(list/mats, coefficient = 1, multiplier = 1, action = "build", name = "design")
if(!_can_use_resource())
return 0
/datum/component/remote_materials/proc/silo_log(obj/machinery/M, action, amount, noun, list/mats)
if (silo)
silo.silo_log(M || parent, action, amount, noun, mats)
var/amount_consumed = mat_container.use_materials(mats, coefficient, multiplier)
if (silo)//log only if silo is linked
var/list/scaled_mats = list()
for(var/i in mats)
scaled_mats[i] = OPTIMAL_COST(OPTIMAL_COST(mats[i] * coefficient) * multiplier)
silo.silo_log(parent, action, -multiplier, name, scaled_mats)
return amount_consumed
/**
* Ejects the given material ref and logs it
*
* Arguments
* [material_ref][datum/material]- The material type you are trying to eject
* eject_amount- how many sheets to eject
* [drop_target][atom]- optional where to drop the sheets. null means it is dropped at this components parent location
*/
/datum/component/remote_materials/proc/eject_sheets(datum/material/material_ref, eject_amount, atom/drop_target = null)
if(!_can_use_resource())
return 0
/// Ejects the given material ref and logs it, or says out loud the problem.
/datum/component/remote_materials/proc/eject_sheets(datum/material/material_ref, eject_amount)
var/atom/movable/movable_parent = parent
if (!istype(movable_parent))
return 0
if(isnull(drop_target))
drop_target = movable_parent.drop_location()
if (!mat_container) //no silolink & local storage not supported
movable_parent.say("No access to material storage, please contact the quartermaster.")
return 0
if(!mat_container.can_hold_material(material_ref)) //material not supported by container
movable_parent.say("Invalid material requested.")
return 0
if(eject_amount <= 0) //invalid amount
movable_parent.say("Invalid amount requested.")
return 0
if(on_hold()) //silo on hold
movable_parent.say("Mineral access is on hold, please contact the quartermaster.")
return 0
var/count = mat_container.retrieve_sheets(eject_amount, material_ref, movable_parent.drop_location())
var/list/matlist = list()
matlist[material_ref] = eject_amount
silo_log(parent, "ejected", -count, "sheets", matlist)
return count
return mat_container.retrieve_sheets(eject_amount, material_ref, target = drop_target, context = parent)