diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 444549bfb6f..d50738621b3 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -463,7 +463,7 @@ All procs that are registered to listen for signals using `RegisterSignal()` mus
```
This is to ensure that it is clear the proc handles signals and turns on a lint to ensure it does not sleep.
-There exists `SIGNAL_HANDLER_DOES_SLEEP`, but this is only for legacy signal handlers that still sleep, new/changed code should not use this.
+Any sleeping behaviour that you need to perform inside a `SIGNAL_HANDLER` proc must be called asynchronously (e.g. with `INVOKE_ASYNC()`) or be redone to work asynchronously.
### Enforcing parent calling
When adding new signals to root level procs, eg;
diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm
index a0080d7266e..2f6b7590f63 100644
--- a/code/__DEFINES/dcs/helpers.dm
+++ b/code/__DEFINES/dcs/helpers.dm
@@ -10,10 +10,6 @@
/// Every proc you pass to RegisterSignal must have this.
#define SIGNAL_HANDLER SHOULD_NOT_SLEEP(TRUE)
-/// Signifies that this proc is used to handle signals, but also sleeps.
-/// Do not use this for new work.
-#define SIGNAL_HANDLER_DOES_SLEEP
-
/// A wrapper for _AddElement that allows us to pretend we're using normal named arguments
#define AddElement(arguments...) _AddElement(list(##arguments))
/// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index c2e5a24fcab..d1be5592eaf 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -316,14 +316,14 @@
if(!(C.datum_flags & DF_SIGNAL_ENABLED))
return NONE
var/proctype = C.signal_procs[src][sigtype]
- return NONE | CallAsync(C, proctype, arguments)
+ return NONE | call(C, proctype)(arglist(arguments))
. = NONE
for(var/I in target)
var/datum/C = I
if(!(C.datum_flags & DF_SIGNAL_ENABLED))
continue
var/proctype = C.signal_procs[src][sigtype]
- . |= CallAsync(C, proctype, arguments)
+ . |= call(C, proctype)(arglist(arguments))
// The type arg is casted so initial works, you shouldn't be passing a real instance into this
/**
diff --git a/code/datums/components/construction.dm b/code/datums/components/construction.dm
index 362cf3c0328..34fa7a0cd7c 100644
--- a/code/datums/components/construction.dm
+++ b/code/datums/components/construction.dm
@@ -32,9 +32,9 @@
update_parent(index)
/datum/component/construction/proc/action(datum/source, obj/item/I, mob/living/user)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
- return check_step(I, user)
+ return INVOKE_ASYNC(src, .proc/check_step, I, user)
/datum/component/construction/proc/update_index(diff)
index += diff
diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm
index 150a9f914fc..c798a10e763 100644
--- a/code/datums/components/embedded.dm
+++ b/code/datums/components/embedded.dm
@@ -185,12 +185,16 @@
/// Called when a carbon with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove()
/datum/component/embedded/proc/ripOut(datum/source, obj/item/I, obj/item/bodypart/limb)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
if(I != weapon || src.limb != limb)
return
var/mob/living/carbon/victim = parent
var/time_taken = rip_time * weapon.w_class
+ INVOKE_ASYNC(src, .proc/complete_rip_out, victim, I, limb, time_taken)
+
+/// everything async that ripOut used to do
+/datum/component/embedded/proc/complete_rip_out(mob/living/carbon/victim, obj/item/I, obj/item/bodypart/limb, time_taken)
victim.visible_message("[victim] attempts to remove [weapon] from [victim.p_their()] [limb.name].","You attempt to remove [weapon] from your [limb.name]... (It will take [DisplayTimeText(time_taken)].)")
if(!do_after(victim, time_taken, target = victim))
return
diff --git a/code/datums/components/gunpoint.dm b/code/datums/components/gunpoint.dm
index 9e2ba76c874..184d2f66f9e 100644
--- a/code/datums/components/gunpoint.dm
+++ b/code/datums/components/gunpoint.dm
@@ -117,8 +117,10 @@
///Bang bang, we're firing a charged shot off
/datum/component/gunpoint/proc/trigger_reaction()
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
+ INVOKE_ASYNC(src, .proc/async_trigger_reaction)
+/datum/component/gunpoint/proc/async_trigger_reaction()
var/mob/living/shooter = parent
shooter.remove_status_effect(STATUS_EFFECT_HOLDUP) // try doing these before the trigger gets pulled since the target (or shooter even) may not exist after pulling the trigger, dig?
target.remove_status_effect(STATUS_EFFECT_HELDUP, shooter)
diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm
index 9b50b5d62df..539b19c4caf 100644
--- a/code/datums/components/omen.dm
+++ b/code/datums/components/omen.dm
@@ -51,7 +51,7 @@
* We do the prob() at the beginning to A. add some tension for /when/ it will strike, and B. (more importantly) ameliorate the fact that we're checking up to 5 turfs's contents each time
*/
/datum/component/omen/proc/check_accident(atom/movable/our_guy)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
if(!isliving(our_guy))
return
@@ -66,7 +66,7 @@
to_chat(living_guy, "A malevolent force launches your body to the floor...")
var/obj/machinery/door/airlock/darth_airlock = turf_content
living_guy.apply_status_effect(STATUS_EFFECT_PARALYZED, 10)
- darth_airlock.close(force_crush = TRUE)
+ INVOKE_ASYNC(darth_airlock, /obj/machinery/door/airlock.proc/close, TRUE)
if(!permanent)
qdel(src)
return
@@ -84,7 +84,7 @@
for(var/obj/machinery/vending/darth_vendor in the_turf)
if(darth_vendor.tiltable)
to_chat(living_guy, "A malevolent force tugs at the [darth_vendor]...")
- darth_vendor.tilt(living_guy)
+ INVOKE_ASYNC(darth_vendor, /obj/machinery/vending.proc/tilt, living_guy)
if(!permanent)
qdel(src)
return
diff --git a/code/datums/components/storage/concrete/wallet.dm b/code/datums/components/storage/concrete/wallet.dm
index c019bb0a596..03a95b50ca1 100644
--- a/code/datums/components/storage/concrete/wallet.dm
+++ b/code/datums/components/storage/concrete/wallet.dm
@@ -8,11 +8,6 @@
var/obj/item/storage/wallet/A = parent
if(istype(A) && A.front_id && !issilicon(user) && !(A.item_flags & IN_STORAGE)) //if it's a wallet in storage seeing the full inventory is more useful
var/obj/item/I = A.front_id
- A.add_fingerprint(user)
- remove_from_storage(I, get_turf(user))
- if(!user.put_in_hands(I))
- to_chat(user, "You fumble for [I] and it falls on the floor.")
- return
- user.visible_message("[user] draws [I] from [parent]!", "You draw [I] from [parent].")
+ INVOKE_ASYNC(src, .proc/attempt_put_in_hands, I, user)
return
- ..()
+ return ..()
diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm
index fac59475e69..bc7d999cdcb 100644
--- a/code/datums/components/storage/storage.dm
+++ b/code/datums/components/storage/storage.dm
@@ -194,7 +194,7 @@
INVOKE_ASYNC(src, .proc/quick_empty, M)
/datum/component/storage/proc/preattack_intercept(datum/source, obj/O, mob/M, params)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE))
return FALSE
@@ -209,19 +209,23 @@
return
if(!isturf(I.loc))
return
- var/list/things = I.loc.contents.Copy()
+ INVOKE_ASYNC(src, .proc/async_preattack_intercept, I, M)
+
+///async functionality from preattack_intercept
+/datum/component/storage/proc/async_preattack_intercept(obj/item/attack_item, mob/pre_attack_mob)
+ var/list/things = attack_item.loc.contents.Copy()
if(collection_mode == COLLECT_SAME)
- things = typecache_filter_list(things, typecacheof(I.type))
+ things = typecache_filter_list(things, typecacheof(attack_item.type))
var/len = length(things)
if(!len)
- to_chat(M, "You failed to pick up anything with [parent]!")
+ to_chat(pre_attack_mob, "You failed to pick up anything with [parent]!")
return
- var/datum/progressbar/progress = new(M, len, I.loc)
+ var/datum/progressbar/progress = new(pre_attack_mob, len, attack_item.loc)
var/list/rejections = list()
- while(do_after(M, 1 SECONDS, parent, NONE, FALSE, CALLBACK(src, .proc/handle_mass_pickup, things, I.loc, rejections, progress)))
+ while(do_after(pre_attack_mob, 1 SECONDS, parent, NONE, FALSE, CALLBACK(src, .proc/handle_mass_pickup, things, attack_item.loc, rejections, progress)))
stoplag(1)
progress.end_progress()
- to_chat(M, "You put everything you could [insert_preposition] [parent].")
+ to_chat(pre_attack_mob, "You put everything you could [insert_preposition] [parent].")
/datum/component/storage/proc/handle_mass_item_insertion(list/things, datum/component/storage/src_object, mob/user, datum/progressbar/progress)
var/atom/source_real_location = src_object.real_location()
@@ -758,7 +762,7 @@
return max(0, max_items - real_location.contents.len)
/datum/component/storage/proc/signal_fill_type(datum/source, type, amount = 20, force = FALSE)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
var/atom/real_location = real_location()
if(!force)
@@ -766,9 +770,8 @@
for(var/i in 1 to amount)
if(!handle_item_insertion(new type(real_location), TRUE))
return i > 1 //return TRUE only if at least one insertion has been successful.
- if(CHECK_TICK)
- if(QDELETED(src))
- return TRUE
+ if(QDELETED(src))
+ return TRUE
return TRUE
@@ -833,7 +836,7 @@
return hide_from(target)
/datum/component/storage/proc/on_alt_click(datum/source, mob/user)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
if(!isliving(user) || !user.CanReach(parent) || user.incapacitated())
return
@@ -849,15 +852,22 @@
A.do_jiggle() //SKYRAT EDIT ADDITION - AESTHETICS
return
- var/obj/item/I = locate() in real_location()
- if(!I)
+ var/obj/item/to_remove = locate() in real_location()
+ if(!to_remove)
return
- A.add_fingerprint(user)
- remove_from_storage(I, get_turf(user))
- if(!user.put_in_hands(I))
- to_chat(user, "You fumble for [I] and it falls on the floor.")
+
+ INVOKE_ASYNC(src, .proc/attempt_put_in_hands, to_remove, user)
+
+///attempt to put an item from contents into the users hands
+/datum/component/storage/proc/attempt_put_in_hands(obj/item/to_remove, mob/user)
+ var/atom/parent_as_atom = parent
+
+ parent_as_atom.add_fingerprint(user)
+ remove_from_storage(to_remove, get_turf(user))
+ if(!user.put_in_hands(to_remove))
+ to_chat(user, "You fumble for [to_remove] and it falls on the floor.")
return
- user.visible_message("[user] draws [I] from [parent]!", "You draw [I] from [parent].")
+ user.visible_message("[user] draws [to_remove] from [parent]!", "You draw [to_remove] from [parent].")
/datum/component/storage/proc/action_trigger(datum/signal_source, datum/action/source)
SIGNAL_HANDLER
diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm
index 98239bcc48d..561e989d640 100644
--- a/code/datums/components/tackle.dm
+++ b/code/datums/components/tackle.dm
@@ -141,7 +141,7 @@
* Finally, we return a bitflag to [COMSIG_MOVABLE_IMPACT] that forces the hitpush to false so that we don't knock them away.
*/
/datum/component/tackler/proc/sack(mob/living/carbon/user, atom/hit)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
if(!tackling || !tackle)
return
@@ -149,7 +149,7 @@
user.toggle_throw_mode()
if(!iscarbon(hit))
if(hit.density)
- return splat(user, hit)
+ INVOKE_ASYNC(src, .proc/splat, user, hit)
return
var/mob/living/carbon/target = hit
@@ -210,7 +210,7 @@
target.Paralyze(5)
target.Knockdown(30)
if(ishuman(target) && ishuman(user))
- S.dna.species.grab(S, T)
+ INVOKE_ASYNC(S.dna.species, /datum/species.proc/grab, S, T)
S.setGrabState(GRAB_PASSIVE)
if(5 to INFINITY) // absolutely BODIED
@@ -224,7 +224,7 @@
target.Paralyze(5)
target.Knockdown(30)
if(ishuman(target) && ishuman(user))
- S.dna.species.grab(S, T)
+ INVOKE_ASYNC(S.dna.species, /datum/species.proc/grab, S, T)
S.setGrabState(GRAB_AGGRESSIVE)
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index b7e923d7800..259f8029a9d 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -156,13 +156,13 @@
///Handles stinging without verbs.
/datum/antagonist/changeling/proc/stingAtom(mob/living/carbon/ling, atom/A)
- SIGNAL_HANDLER_DOES_SLEEP
+ SIGNAL_HANDLER
if(!chosen_sting || A == ling || !istype(ling) || ling.stat)
return
- if(!chosen_sting.try_to_sting(ling, A))
- return
- ling.changeNext_move(CLICK_CD_MELEE)
+
+ INVOKE_ASYNC(chosen_sting, /datum/action/changeling/sting.proc/try_to_sting, ling, A)
+
return COMSIG_MOB_CANCEL_CLICKON
/datum/antagonist/changeling/proc/has_sting(datum/action/changeling/power)
diff --git a/code/modules/antagonists/changeling/changeling_power.dm b/code/modules/antagonists/changeling/changeling_power.dm
index 4fab82033f7..38ba611a079 100644
--- a/code/modules/antagonists/changeling/changeling_power.dm
+++ b/code/modules/antagonists/changeling/changeling_power.dm
@@ -53,6 +53,7 @@ the same goes for Remove(). if you override Remove(), call parent or else your p
if(sting_action(user, target))
sting_feedback(user, target)
c.chem_charges -= chemical_cost
+ user.changeNext_move(CLICK_CD_MELEE)
return TRUE
return FALSE
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index db55c297a73..f90ab14fcda 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -96,16 +96,6 @@
spreadFire(AM)
/mob/living/carbon/human/Topic(href, href_list)
- if(href_list["embedded_object"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERITY))
- var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
- if(!L)
- return
- var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
- if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
- return
- SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L)
- return
-
if(href_list["item"]) //canUseTopic check for this is handled by mob/Topic()
var/slot = text2num(href_list["item"])
if(check_obscured_slots(TRUE) & slot)
diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm
index 198ac970fab..b8476b9cd9e 100644
--- a/code/modules/vehicles/mecha/mecha_construction_paths.dm
+++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm
@@ -421,7 +421,7 @@
outer_plating_amount=1
/datum/component/construction/mecha/gygax/action(datum/source, atom/used_atom, mob/user)
- return check_step(used_atom,user)
+ return INVOKE_ASYNC(src, .proc/check_step, used_atom,user)
/datum/component/construction/mecha/gygax/custom_action(obj/item/I, mob/living/user, diff)
if(!..())
diff --git a/modular_skyrat/modules/sec_haul/code/peacekeeper/peacekeeper_clothing.dm b/modular_skyrat/modules/sec_haul/code/peacekeeper/peacekeeper_clothing.dm
index 5072a084547..28aff04604c 100644
--- a/modular_skyrat/modules/sec_haul/code/peacekeeper/peacekeeper_clothing.dm
+++ b/modular_skyrat/modules/sec_haul/code/peacekeeper/peacekeeper_clothing.dm
@@ -181,8 +181,6 @@
component_type = /datum/component/storage/concrete/peacekeeper
/datum/component/storage/concrete/peacekeeper/on_alt_click(datum/source, mob/user)
- SIGNAL_HANDLER_DOES_SLEEP
-
if(!isliving(user) || !user.CanReach(parent) || user.incapacitated())
return
if(locked)
@@ -191,16 +189,14 @@
var/atom/A = parent
- var/obj/item/gun/ballistic/automatic/pistol/P = locate() in real_location()
- if(!P)
- return
+ var/obj/item/gun/ballistic/automatic/pistol/gun_to_draw = locate() in real_location()
+ if(!gun_to_draw)
+ return ..()
A.add_fingerprint(user)
- remove_from_storage(P, get_turf(user))
+ remove_from_storage(gun_to_draw, get_turf(user))
playsound(parent, 'modular_skyrat/modules/sec_haul/sound/holsterout.ogg', 50, TRUE, -5)
- if(!user.put_in_hands(P))
- to_chat(user, "You fumble for [P] and it falls on the floor.")
- return
- user.visible_message("[user] draws [P] from [parent]!", "You draw [P] from [parent].")
+ INVOKE_ASYNC(user, /mob/.proc/put_in_hands, gun_to_draw)
+ user.visible_message("[user] draws [gun_to_draw] from [parent]!", "You draw [gun_to_draw] from [parent].")
/datum/component/storage/concrete/peacekeeper/mob_item_insertion_feedback(mob/user, mob/M, obj/item/I, override = FALSE)
diff --git a/modular_skyrat/modules/server_overflow/code/chat_link.dm b/modular_skyrat/modules/server_overflow/code/chat_link.dm
new file mode 100644
index 00000000000..64b7ddb4dbe
--- /dev/null
+++ b/modular_skyrat/modules/server_overflow/code/chat_link.dm
@@ -0,0 +1,35 @@
+
+
+/proc/send_ooc_to_other_server(ckey, message)
+ if(!CONFIG_GET(flag/secondary_server_enabled))
+ return
+ var/list/ooc_information = list()
+ ooc_information["server_name"] = CONFIG_GET(string/our_server_name)
+ ooc_information["expected_ckey"] = ckey(ckey)
+ ooc_information["message"] = message
+ var/second_server = CONFIG_GET(string/server_two_ip)
+ if(!second_server)
+ message_admins("SERVER CONTROL CRITICAL ERROR: No second server IP set in config!")
+ return
+ send2otherserver(station_name(), null, "incoming_ooc_message", second_server, ooc_information)
+
+/datum/world_topic/incoming_ooc_message
+ keyword = "incoming_ooc_message"
+ require_comms_key = TRUE
+
+/datum/world_topic/incoming_ooc_message/Run(list/input)
+ var/server_name = input["server_name"]
+ var/exp_ckey = ckey(input["expected_ckey"])
+ var/message = input["message"]
+
+ send_ooc_message("[server_name] - [exp_ckey]", message)
+
+/proc/send_ooc_message(sender_name, message)
+ if(!GLOB.ooc_allowed)
+ return
+ for(var/client/C in GLOB.clients)
+ if(C.prefs.chat_toggles & CHAT_OOC)
+ if(GLOB.OOC_COLOR)
+ to_chat(C, "OOC: [sender_name]: [message]")
+ else
+ to_chat(C, "OOC: [sender_name]: [message]")