mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-20 11:40:07 +01:00
## About The Pull Request Refactors the way we listen for reagent changes. The changes made can be listed as points **1. Removes `COMSIG_REAGENTS_PRE_ADD_REAGENT`** Used to stop new reagents from being added to the holder, its only application is with the BRPED to stop inserting reagents into beakers/cells stored inside it. Rather than using this signal a cleaner solution is to simply remove the component part's reagent holders' flags which allow us to insert reagents into it(i.e. `REFILABLE`, `INJECTIBLE`, `DRAINABLE`) and restore them back when that part is removed thus achieving the same results. Thus `add_reagent()` is now slightly faster because it no longer uses this signal **2. Removes every other signal used by the reagent holder** Removes pretty much every other signal used by `holder.dm` which are `COMSIG_REAGENTS_[NEW_REAGENT, ADD_REAGENT, DEL_REAGENT, REM_REAGENT, CLEAR_REAGENTS]` While yes, it is true that all these signals are unique & serve a specific purpose the problem is no object in code respects their uniqueness & instead clumps them up all together & hooks them onto one proc to listen for "reagent changes". You see this code pattern repeated in so many places https://github.com/tgstation/tgstation/blob/9277364ef6449262e2c693ff6817925e074c47ce/code/modules/power/power_store.dm#L105 Not only does this look ugly but it also has a memory overhead (4 to 5 signal slots all performing the same action which is a lot compared to the solution i implemented below). Bonus is that "none" of the parameters passed to this proc are used so they go to waste as well. So after removing a ton of code we need something that can still make the code function which brings us to point 3 **3. Adds a new signal `COMSIG_REAGENTS_HOLDER_UPDATED` to rule them all** So if all objects in game are listening for "reagent changes"[adding/removing, reagents] then we need to look at the proc that is always called during these changes & that is none other than `update_total()` so we let that send out a signal and cause all objects to hook onto this 1 signal instead of 4 to 5 signals as explained in point 2 ## Why It's Good For The Game This section isn't necessary but i want us to better appreciate both the code & performance benifits of this PR. 1. First of all its waaaay less code and signals to worry about. Just look at the number of lines of code removed compared to added. Nothing more to say 2. Overhead of `RegisterSignal` compared to `RegisterSignals` is less for obvious reasons 3. `remove_all` is significantly faster as it no longer calls `remove_reagent()`[which in turn calls `update_total()` & `handle_reactions()` per call & uses a for loop so its a nested for loop of doom] for every reagent it removes, instead it does the work by itself & calls the above 2 procs just once 4. Usually when a reagent is deleted it calls `COMSIG_REAGENTS_REM_REAGENT` & `COMSIG_REAGENTS_DEL_REAGENT`. So if you have a holder with like 3 reagents upon transferring/deleting them you get a total of 6 signal calls!!. Now it's just 3(when using `trans_to`) and just 1 when using `remove_all/clear_reagents`. Need i say more no ## Changelog 🆑 fix: hydrophonics circuit component actually sets output level when reagents are changed in the tray refactor: refactors how code listens for reagent changes. Report bugs on github /🆑
170 lines
7.2 KiB
Plaintext
170 lines
7.2 KiB
Plaintext
///RPED. Allows installing & exchaging parts on machines
|
|
/obj/item/storage/part_replacer
|
|
name = "rapid part exchange device"
|
|
desc = "Special mechanical module made to store, sort, and apply standard machine parts."
|
|
icon_state = "RPED"
|
|
inhand_icon_state = "RPED"
|
|
worn_icon_state = "RPED"
|
|
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
|
|
w_class = WEIGHT_CLASS_HUGE
|
|
storage_type = /datum/storage/rped
|
|
|
|
/obj/item/storage/part_replacer/interact_with_atom(obj/attacked_object, mob/living/user, list/modifiers)
|
|
if(user.combat_mode)
|
|
return ITEM_INTERACT_SKIP_TO_ATTACK
|
|
|
|
//its very important to NOT block so frames can still interact with it
|
|
if(!ismachinery(attacked_object) || istype(attacked_object, /obj/machinery/computer))
|
|
return NONE
|
|
|
|
var/obj/machinery/attacked_machinery = attacked_object
|
|
if(!LAZYLEN(attacked_machinery.component_parts))
|
|
return ITEM_INTERACT_FAILURE
|
|
|
|
return attacked_machinery.exchange_parts(user, src) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_FAILURE
|
|
|
|
///Plays the sound for RPED exhanging or installing parts.
|
|
/obj/item/storage/part_replacer/proc/play_rped_sound()
|
|
playsound(src, 'sound/items/tools/rped.ogg', 40, TRUE)
|
|
|
|
/**
|
|
* Gets parts sorted in order of their tier
|
|
* Arguments
|
|
*
|
|
* * ignore_stacks - should the final list contain stacks
|
|
*/
|
|
/obj/item/storage/part_replacer/proc/get_sorted_parts(ignore_stacks = FALSE)
|
|
RETURN_TYPE(/list/obj/item)
|
|
|
|
var/list/obj/item/part_list = list()
|
|
//Assemble a list of current parts, then sort them by their rating!
|
|
for(var/obj/item/component_part in contents)
|
|
//No need to put circuit boards in this list or stacks when exchanging parts
|
|
if(istype(component_part, /obj/item/circuitboard) || (ignore_stacks && istype(component_part, /obj/item/stack)))
|
|
continue
|
|
part_list += component_part
|
|
//Sort the parts. This ensures that higher tier items are applied first.
|
|
sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort))
|
|
|
|
return part_list
|
|
|
|
///Bluespace RPED. Allows exchanging parts from a distance & through cameras
|
|
/obj/item/storage/part_replacer/bluespace
|
|
name = "bluespace rapid part exchange device"
|
|
desc = "A version of the RPED that allows for replacement of parts and scanning from a distance, along with higher capacity for parts."
|
|
icon_state = "BS_RPED"
|
|
inhand_icon_state = "BS_RPED"
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
storage_type = /datum/storage/rped/bluespace
|
|
|
|
/obj/item/storage/part_replacer/bluespace/Initialize(mapload)
|
|
. = ..()
|
|
|
|
RegisterSignal(src, COMSIG_ATOM_ENTERED, PROC_REF(on_part_entered))
|
|
RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(on_part_exited))
|
|
|
|
/obj/item/storage/part_replacer/bluespace/interact_with_atom(obj/attacked_object, mob/living/user, list/modifiers)
|
|
. = ..()
|
|
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
|
user.Beam(attacked_object, icon_state = "rped_upgrade", time = 0.5 SECONDS)
|
|
|
|
/obj/item/storage/part_replacer/bluespace/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
|
|
return interact_with_atom(interacting_with, user, modifiers)
|
|
|
|
/obj/item/storage/part_replacer/bluespace/play_rped_sound()
|
|
if(prob(1))
|
|
playsound(src, 'sound/items/pshoom/pshoom_2.ogg', 40, TRUE)
|
|
return
|
|
playsound(src, 'sound/items/pshoom/pshoom.ogg', 40, TRUE)
|
|
|
|
/**
|
|
* Signal handler for when a part has been inserted into the BRPED.
|
|
* If the inserted item is a rigged or corrupted cell, does some logging.
|
|
* We clear existing reagents & stop new ones from being added to prevent remote spam bombing
|
|
*/
|
|
/obj/item/storage/part_replacer/bluespace/proc/on_part_entered(datum/source, obj/item/inserted_component)
|
|
SIGNAL_HANDLER
|
|
|
|
if(istype(inserted_component, /obj/item/stock_parts/power_store))
|
|
var/obj/item/stock_parts/power_store/inserted_cell = inserted_component
|
|
if(inserted_cell.rigged || inserted_cell.corrupted)
|
|
message_admins("[ADMIN_LOOKUPFLW(usr)] has inserted rigged/corrupted [inserted_cell] into [src].")
|
|
usr.log_message("has inserted rigged/corrupted [inserted_cell] into [src].", LOG_GAME)
|
|
usr.log_message("inserted rigged/corrupted [inserted_cell] into [src]", LOG_ATTACK)
|
|
return
|
|
|
|
var/datum/reagents/target_holder = inserted_component.reagents
|
|
if(target_holder)
|
|
if(target_holder.total_volume)
|
|
target_holder.force_stop_reacting()
|
|
target_holder.clear_reagents()
|
|
to_chat(usr, span_notice("[src] churns as [inserted_component] has its reagents emptied into bluespace."))
|
|
target_holder.flags = target_holder.flags << 5 //masks all flags upto DUNKABLE(1<<5) i.e. removes all methods of transfering reagents to/from the object
|
|
/**
|
|
* Signal handler for a part is removed from the BRPED.
|
|
* Restores original reagents of the component part, if it has any.
|
|
*/
|
|
/obj/item/storage/part_replacer/bluespace/proc/on_part_exited(datum/source, obj/item/removed_component)
|
|
SIGNAL_HANDLER
|
|
|
|
var/datum/reagents/target_holder = removed_component.reagents
|
|
if(target_holder)
|
|
target_holder.flags = target_holder.flags >> 5 //restores all flags upto DUNKABLE(1<<5)
|
|
|
|
//RPED with tiered contents
|
|
/obj/item/storage/part_replacer/bluespace/tier1/PopulateContents()
|
|
for(var/i in 1 to 10)
|
|
new /obj/item/stock_parts/capacitor(src)
|
|
new /obj/item/stock_parts/scanning_module(src)
|
|
new /obj/item/stock_parts/servo(src)
|
|
new /obj/item/stock_parts/micro_laser(src)
|
|
new /obj/item/stock_parts/matter_bin(src)
|
|
new /obj/item/stock_parts/power_store/cell/high(src)
|
|
|
|
/obj/item/storage/part_replacer/bluespace/tier2/PopulateContents()
|
|
for(var/i in 1 to 10)
|
|
new /obj/item/stock_parts/capacitor/adv(src)
|
|
new /obj/item/stock_parts/scanning_module/adv(src)
|
|
new /obj/item/stock_parts/servo/nano(src)
|
|
new /obj/item/stock_parts/micro_laser/high(src)
|
|
new /obj/item/stock_parts/matter_bin/adv(src)
|
|
new /obj/item/stock_parts/power_store/cell/super(src)
|
|
|
|
/obj/item/storage/part_replacer/bluespace/tier3/PopulateContents()
|
|
for(var/i in 1 to 10)
|
|
new /obj/item/stock_parts/capacitor/super(src)
|
|
new /obj/item/stock_parts/scanning_module/phasic(src)
|
|
new /obj/item/stock_parts/servo/pico(src)
|
|
new /obj/item/stock_parts/micro_laser/ultra(src)
|
|
new /obj/item/stock_parts/matter_bin/super(src)
|
|
new /obj/item/stock_parts/power_store/cell/hyper(src)
|
|
|
|
/obj/item/storage/part_replacer/bluespace/tier4/PopulateContents()
|
|
for(var/i in 1 to 10)
|
|
new /obj/item/stock_parts/capacitor/quadratic(src)
|
|
new /obj/item/stock_parts/scanning_module/triphasic(src)
|
|
new /obj/item/stock_parts/servo/femto(src)
|
|
new /obj/item/stock_parts/micro_laser/quadultra(src)
|
|
new /obj/item/stock_parts/matter_bin/bluespace(src)
|
|
new /obj/item/stock_parts/power_store/cell/bluespace(src)
|
|
|
|
//used in a cargo crate
|
|
/obj/item/storage/part_replacer/cargo/PopulateContents()
|
|
for(var/i in 1 to 10)
|
|
new /obj/item/stock_parts/capacitor(src)
|
|
new /obj/item/stock_parts/scanning_module(src)
|
|
new /obj/item/stock_parts/servo(src)
|
|
new /obj/item/stock_parts/micro_laser(src)
|
|
new /obj/item/stock_parts/matter_bin(src)
|
|
|
|
///Cyborg variant
|
|
/obj/item/storage/part_replacer/cyborg
|
|
name = "rapid part exchange device"
|
|
desc = "Special mechanical module made to store, sort, and apply standard machine parts. This one has an extra large compartment for more parts."
|
|
icon_state = "borgrped"
|
|
inhand_icon_state = "RPED"
|
|
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
|
|
storage_type = /datum/storage/rped/bluespace
|