mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-14 19:51:59 +00:00
* EVEN MORE HARDDEL FIXES (#60228) Fixes a ton of harddels, sourced from #59996 I think this brings us down to like, ~100 per round from ~200, with only like 20 of those being proper hell failures. I've seen harddel profiles below 1 second of total cost. Feeling good. See you on the other side Makes the cryopod control computer into a weakref, never trust bee code Converts brig door timer internal lists to weakrefs Fixes a harddel caused by qdeling a motion sensitive camera after it had left its source area, jesus christ why didn't we do this already holy shit Converts the radio implant ref held by the antenna mutation to weakrefs because it isn't reliably cleaned up, makes the radio implant actually qdel its fucking radio Removes the target var from the throwing datum, it does literally nothing and just exists to cause harddels, mostly for the singularity Fixes a cable harddel sourced from things that try to enter blueprints after smoothing, but before roundstart. IE, shuttles. Removes shuttles from the blueprints Fixes emmisive blockers being added post qdel Removes some manual ghosting from cryopods, I initially did this for harddel reasons, but I figured out a better fix for that. I'm now doing it because it's got this really strange logic for like "re-entering the game" that doesn't actually link to what the ghostize proc does. We should remove this at some point Fixes robot hud objects harddeling due to hanging refs Fixes buildmode related hanging refs, I'm coming for you admin team Fixes a few instances of trying to add the forensics component post qdel, hhhhhhhhhhh Fixes some split personality harddels/weirdness Replaces a use of disconnect_duct with an init qdel hint, I suspect there's more issues with duct harddels, I've seen some odd logs about ahhh the area_contents list, but we can worry about that later Makes teleporter targets into weakrefs, properly types them as /atom Makes frequency devices into weakrefs Makes cameras remove themselves from camera nets on Destroy Makes tgui ui datums implement destroy, this means if I ever see one hang a ref to user or whatever, I know there's an error with calling close() properly. I've seen this harddel once, but not after this change so I assume there was some error with close(). IDK maybe this is a papering over? Would have to ask @ stylemistake I've seen logs of beartraps being in world post del, putting a return there just in case. The same is true of nerf darts, but I haven't really looked into that yet Makes a shoe's ref to untying alerts a weakref, yes this is needed. Moves clearing client_in_contents to the Login of the new mob. This prevents doing things like ghosting someone before a mob qdel causing harddels Fixes a harddel set sourced from adding a status effect to a qdeleted thing. Is this an error? I'm honestly not sure. Converts bsa code to weakrefs Converts the partner var of heat exchangers to weakrefs Converts camera assemblies to weakrefs Fixes some dumb behavior with ammo casings and assuming you'll be on a turf post Destroy parent call Fixes? merger related harddels, you were never cleared from your own members list, so origin objects would end up making a new list, creating harddels. Potential input from @ ninjanomnom about the logic Chasms store a static list of "falling atoms", which only exists for chasms that go somewhere else. This list wasn't being cleared of qdeleted objects, which is what happens when you fall in most chasms. Fixes this, and converts the list to weakrefs. Fixes some runtimes in both sheet code, and the weather listener element. This is here because runtime spam made testing more of a pain, didn't think it needed its own pr Fixes colorful reagent harddels sourced from reagents that were qdel'd before roundstart. I'm only like 50% sure this actually got it, but the issue may have been solved by #60174, so eh Turns the nuke op antag datum's ref to the war button into a weakref Fixes some holopad code that was not nulling refs all the time Converts camera bugs to weakrefs, this was the result of the bug being "reworked" like 6 years back without taking the existing ref clearing into account. Whole item needs a redo, but this'll do for now. Ensures that the both pulling and pullee refs are cleared on Destroy The crew monitor held all users in a non clearing list, makes that list a weakref because I hate everything Oh and I removed all sources of gas_mixture qdeletion, I'm kinda unsure on this since it's not technically supported, but any harddels from it might? indicate something going wrong with like, gas passing logic. I'd like @ MrStonedOne's thoughts, since I trust him to call me an idiot if I'm wrong. <!-- Please add a short description of why you think these changes would benefit the game. If you can't justify it in words, it might not be worth adding. --> ## Why it's not good for the game I crashed sybil like 10 times to get this data, I'm gonna put it to good use. Don't think you're safe sybilites, I'm coming for you. * EVEN MORE HARDDEL FIXES Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
468 lines
14 KiB
Plaintext
468 lines
14 KiB
Plaintext
#define HOLOPAD_MAX_DIAL_TIME 200
|
|
|
|
#define HOLORECORD_DELAY "delay"
|
|
#define HOLORECORD_SAY "say"
|
|
#define HOLORECORD_SOUND "sound"
|
|
#define HOLORECORD_LANGUAGE "lang"
|
|
#define HOLORECORD_PRESET "preset"
|
|
#define HOLORECORD_RENAME "rename"
|
|
|
|
#define HOLORECORD_MAX_LENGTH 200
|
|
|
|
/mob/camera/ai_eye/remote/holo/setLoc()
|
|
. = ..()
|
|
var/obj/machinery/holopad/H = origin
|
|
H?.move_hologram(eye_user, loc)
|
|
|
|
/obj/machinery/holopad/remove_eye_control(mob/living/user)
|
|
if(user.client)
|
|
user.reset_perspective(null)
|
|
user.remote_control = null
|
|
|
|
//this datum manages it's own references
|
|
|
|
/datum/holocall
|
|
var/mob/living/user //the one that called
|
|
var/obj/machinery/holopad/calling_holopad //the one that sent the call
|
|
var/obj/machinery/holopad/connected_holopad //the one that answered the call (may be null)
|
|
var/list/dialed_holopads //all things called, will be cleared out to just connected_holopad once answered
|
|
|
|
var/mob/camera/ai_eye/remote/holo/eye //user's eye, once connected
|
|
var/obj/effect/overlay/holo_pad_hologram/hologram //user's hologram, once connected
|
|
var/datum/action/innate/end_holocall/hangup //hangup action
|
|
|
|
var/call_start_time
|
|
var/head_call = FALSE //calls from a head of staff autoconnect, if the receiving pad is not secure.
|
|
|
|
//creates a holocall made by `caller` from `calling_pad` to `callees`
|
|
/datum/holocall/New(mob/living/caller, obj/machinery/holopad/calling_pad, list/callees, elevated_access = FALSE)
|
|
call_start_time = world.time
|
|
user = caller
|
|
calling_pad.outgoing_call = src
|
|
calling_holopad = calling_pad
|
|
head_call = elevated_access
|
|
dialed_holopads = list()
|
|
|
|
for(var/I in callees)
|
|
var/obj/machinery/holopad/H = I
|
|
if(!QDELETED(H) && H.is_operational)
|
|
dialed_holopads += H
|
|
if(head_call)
|
|
if(H.secure)
|
|
calling_pad.say("Auto-connection refused, falling back to call mode.")
|
|
H.say("Incoming call.")
|
|
else
|
|
H.say("Incoming connection.")
|
|
else
|
|
H.say("Incoming call.")
|
|
LAZYADD(H.holo_calls, src)
|
|
|
|
if(!dialed_holopads.len)
|
|
calling_pad.say("Connection failure.")
|
|
qdel(src)
|
|
return
|
|
|
|
testing("Holocall started")
|
|
|
|
//cleans up ALL references :)
|
|
/datum/holocall/Destroy()
|
|
QDEL_NULL(hangup)
|
|
|
|
if(!QDELETED(eye))
|
|
QDEL_NULL(eye)
|
|
|
|
if(connected_holopad && !QDELETED(hologram))
|
|
hologram = null
|
|
connected_holopad.clear_holo(user)
|
|
|
|
user = null
|
|
|
|
//Hologram survived holopad destro
|
|
if(!QDELETED(hologram))
|
|
hologram.HC = null
|
|
QDEL_NULL(hologram)
|
|
hologram = null
|
|
|
|
for(var/I in dialed_holopads)
|
|
var/obj/machinery/holopad/H = I
|
|
LAZYREMOVE(H.holo_calls, src)
|
|
dialed_holopads.Cut()
|
|
|
|
if(calling_holopad)
|
|
calling_holopad.calling = FALSE
|
|
calling_holopad.outgoing_call = null
|
|
calling_holopad.SetLightsAndPower()
|
|
calling_holopad = null
|
|
if(connected_holopad)
|
|
connected_holopad.SetLightsAndPower()
|
|
connected_holopad = null
|
|
|
|
testing("Holocall destroyed")
|
|
|
|
return ..()
|
|
|
|
//Gracefully disconnects a holopad `H` from a call. Pads not in the call are ignored. Notifies participants of the disconnection
|
|
/datum/holocall/proc/Disconnect(obj/machinery/holopad/H)
|
|
testing("Holocall disconnect")
|
|
if(H == connected_holopad)
|
|
var/area/A = get_area(connected_holopad)
|
|
calling_holopad.say("[A] holopad disconnected.")
|
|
else if(H == calling_holopad && connected_holopad)
|
|
connected_holopad.say("[user] disconnected.")
|
|
|
|
ConnectionFailure(H, TRUE)
|
|
|
|
//Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored.
|
|
/datum/holocall/proc/ConnectionFailure(obj/machinery/holopad/H, graceful = FALSE)
|
|
testing("Holocall connection failure: graceful [graceful]")
|
|
if(H == connected_holopad || H == calling_holopad)
|
|
if(!graceful && H != calling_holopad)
|
|
calling_holopad.say("Connection failure.")
|
|
qdel(src)
|
|
return
|
|
|
|
LAZYREMOVE(H.holo_calls, src)
|
|
dialed_holopads -= H
|
|
if(!dialed_holopads.len)
|
|
if(graceful)
|
|
calling_holopad.say("Call rejected.")
|
|
testing("No recipients, terminating")
|
|
qdel(src)
|
|
|
|
//Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored
|
|
/datum/holocall/proc/Answer(obj/machinery/holopad/H)
|
|
testing("Holocall answer")
|
|
if(H == calling_holopad)
|
|
CRASH("How cute, a holopad tried to answer itself.")
|
|
|
|
if(!(H in dialed_holopads))
|
|
return
|
|
|
|
if(connected_holopad)
|
|
CRASH("Multi-connection holocall")
|
|
|
|
for(var/I in dialed_holopads)
|
|
if(I == H)
|
|
continue
|
|
Disconnect(I)
|
|
|
|
for(var/I in H.holo_calls)
|
|
var/datum/holocall/HC = I
|
|
if(HC != src)
|
|
HC.Disconnect(H)
|
|
|
|
connected_holopad = H
|
|
|
|
if(!Check())
|
|
return
|
|
|
|
calling_holopad.calling = FALSE
|
|
hologram = H.activate_holo(user)
|
|
hologram.HC = src
|
|
|
|
//eyeobj code is horrid, this is the best copypasta I could make
|
|
eye = new
|
|
eye.origin = H
|
|
eye.eye_initialized = TRUE
|
|
eye.eye_user = user
|
|
eye.name = "Camera Eye ([user.name])"
|
|
user.remote_control = eye
|
|
user.reset_perspective(eye)
|
|
eye.setLoc(H.loc)
|
|
|
|
hangup = new(eye, src)
|
|
hangup.Grant(user)
|
|
playsound(H, 'sound/machines/ping.ogg', 100)
|
|
H.say("Connection established.")
|
|
|
|
//Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise
|
|
/datum/holocall/proc/Check()
|
|
for(var/I in dialed_holopads)
|
|
var/obj/machinery/holopad/H = I
|
|
if(!H.is_operational)
|
|
ConnectionFailure(H)
|
|
|
|
if(QDELETED(src))
|
|
return FALSE
|
|
|
|
. = !QDELETED(user) && !user.incapacitated() && !QDELETED(calling_holopad) && calling_holopad.is_operational && user.loc == calling_holopad.loc
|
|
|
|
if(.)
|
|
if(!connected_holopad)
|
|
. = world.time < (call_start_time + HOLOPAD_MAX_DIAL_TIME)
|
|
if(!.)
|
|
calling_holopad.say("No answer received.")
|
|
|
|
if(!.)
|
|
testing("Holocall Check fail")
|
|
qdel(src)
|
|
|
|
/datum/action/innate/end_holocall
|
|
name = "End Holocall"
|
|
icon_icon = 'icons/mob/actions/actions_silicon.dmi'
|
|
button_icon_state = "camera_off"
|
|
var/datum/holocall/hcall
|
|
|
|
/datum/action/innate/end_holocall/New(Target, datum/holocall/HC)
|
|
..()
|
|
hcall = HC
|
|
|
|
/datum/action/innate/end_holocall/Activate()
|
|
hcall.Disconnect(hcall.calling_holopad)
|
|
|
|
|
|
//RECORDS
|
|
/datum/holorecord
|
|
var/caller_name = "Unknown" //Caller name
|
|
var/image/caller_image
|
|
var/list/entries = list()
|
|
var/language = /datum/language/common //Initial language, can be changed by HOLORECORD_LANGUAGE entries
|
|
|
|
/datum/holorecord/proc/set_caller_image(mob/user)
|
|
var/olddir = user.dir
|
|
user.setDir(SOUTH)
|
|
caller_image = image(user)
|
|
user.setDir(olddir)
|
|
|
|
/obj/item/disk/holodisk
|
|
name = "holorecord disk"
|
|
desc = "Stores recorder holocalls."
|
|
icon_state = "holodisk"
|
|
obj_flags = UNIQUE_RENAME
|
|
custom_materials = list(/datum/material/iron = 100, /datum/material/glass = 100)
|
|
var/datum/holorecord/record
|
|
//Preset variables
|
|
var/preset_image_type
|
|
var/preset_record_text
|
|
|
|
/obj/item/disk/holodisk/Initialize(mapload)
|
|
. = ..()
|
|
if(preset_record_text)
|
|
INVOKE_ASYNC(src, .proc/build_record)
|
|
|
|
/obj/item/disk/holodisk/Destroy()
|
|
QDEL_NULL(record)
|
|
return ..()
|
|
|
|
/obj/item/disk/holodisk/attackby(obj/item/W, mob/user, params)
|
|
if(istype(W, /obj/item/disk/holodisk))
|
|
var/obj/item/disk/holodisk/holodiskOriginal = W
|
|
if (holodiskOriginal.record)
|
|
if (!record)
|
|
record = new
|
|
record.caller_name = holodiskOriginal.record.caller_name
|
|
record.caller_image = holodiskOriginal.record.caller_image
|
|
record.entries = holodiskOriginal.record.entries.Copy()
|
|
record.language = holodiskOriginal.record.language
|
|
to_chat(user, span_notice("You copy the record from [holodiskOriginal] to [src] by connecting the ports!"))
|
|
name = holodiskOriginal.name
|
|
else
|
|
to_chat(user, span_warning("[holodiskOriginal] has no record on it!"))
|
|
..()
|
|
|
|
/obj/item/disk/holodisk/proc/build_record()
|
|
record = new
|
|
var/list/lines = splittext(preset_record_text,"\n")
|
|
for(var/line in lines)
|
|
var/prepared_line = trim(line)
|
|
if(!length(prepared_line))
|
|
continue
|
|
var/splitpoint = findtext(prepared_line," ")
|
|
if(!splitpoint)
|
|
continue
|
|
var/command = copytext(prepared_line, 1, splitpoint)
|
|
var/value = copytext(prepared_line, splitpoint + length(prepared_line[splitpoint]))
|
|
switch(command)
|
|
if("DELAY")
|
|
var/delay_value = text2num(value)
|
|
if(!delay_value)
|
|
continue
|
|
record.entries += list(list(HOLORECORD_DELAY,delay_value))
|
|
if("NAME")
|
|
if(!record.caller_name)
|
|
record.caller_name = value
|
|
else
|
|
record.entries += list(list(HOLORECORD_RENAME,value))
|
|
if("SAY")
|
|
record.entries += list(list(HOLORECORD_SAY,value))
|
|
if("SOUND")
|
|
record.entries += list(list(HOLORECORD_SOUND,value))
|
|
if("LANGUAGE")
|
|
var/lang_type = text2path(value)
|
|
if(ispath(lang_type,/datum/language))
|
|
record.entries += list(list(HOLORECORD_LANGUAGE,lang_type))
|
|
if("PRESET")
|
|
var/preset_type = text2path(value)
|
|
if(ispath(preset_type,/datum/preset_holoimage))
|
|
record.entries += list(list(HOLORECORD_PRESET,preset_type))
|
|
if(!preset_image_type)
|
|
record.caller_image = image('icons/mob/animal.dmi',"old")
|
|
else
|
|
var/datum/preset_holoimage/H = new preset_image_type
|
|
record.caller_image = H.build_image()
|
|
|
|
//These build caller image from outfit and some additional data, for use by mappers for ruin holorecords
|
|
/datum/preset_holoimage
|
|
var/nonhuman_mobtype //Fill this if you just want something nonhuman
|
|
var/outfit_type
|
|
var/species_type = /datum/species/human
|
|
|
|
/datum/preset_holoimage/proc/build_image()
|
|
if(nonhuman_mobtype)
|
|
var/mob/living/L = nonhuman_mobtype
|
|
. = image(initial(L.icon),initial(L.icon_state))
|
|
else
|
|
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy("HOLODISK_PRESET")
|
|
if(species_type)
|
|
mannequin.set_species(species_type)
|
|
if(outfit_type)
|
|
mannequin.equipOutfit(outfit_type,TRUE)
|
|
mannequin.setDir(SOUTH)
|
|
COMPILE_OVERLAYS(mannequin)
|
|
. = image(mannequin)
|
|
unset_busy_human_dummy("HOLODISK_PRESET")
|
|
|
|
/obj/item/disk/holodisk/example
|
|
preset_image_type = /datum/preset_holoimage/clown
|
|
preset_record_text = {"
|
|
NAME Clown
|
|
DELAY 10
|
|
SAY Why did the chaplain cross the maint ?
|
|
DELAY 20
|
|
SAY He wanted to get to the other side!
|
|
SOUND clownstep
|
|
DELAY 30
|
|
LANGUAGE /datum/language/narsie
|
|
SAY Helped him get there!
|
|
DELAY 10
|
|
SAY ALSO IM SECRETLY A GORILLA
|
|
DELAY 10
|
|
PRESET /datum/preset_holoimage/gorilla
|
|
NAME Gorilla
|
|
LANGUAGE /datum/language/common
|
|
SAY OOGA
|
|
DELAY 20"}
|
|
|
|
/datum/preset_holoimage/engineer
|
|
outfit_type = /datum/outfit/job/engineer
|
|
|
|
/datum/preset_holoimage/engineer/rig
|
|
outfit_type = /datum/outfit/job/engineer/gloved/rig
|
|
|
|
/datum/preset_holoimage/engineer/ce
|
|
outfit_type = /datum/outfit/job/ce
|
|
|
|
/datum/preset_holoimage/engineer/ce/rig
|
|
outfit_type = /datum/outfit/job/engineer/gloved/rig
|
|
|
|
/datum/preset_holoimage/engineer/atmos
|
|
outfit_type = /datum/outfit/job/atmos
|
|
|
|
/datum/preset_holoimage/engineer/atmos/rig
|
|
outfit_type = /datum/outfit/job/engineer/gloved/rig
|
|
|
|
/datum/preset_holoimage/researcher
|
|
outfit_type = /datum/outfit/job/scientist
|
|
|
|
/datum/preset_holoimage/captain
|
|
outfit_type = /datum/outfit/job/captain
|
|
|
|
/datum/preset_holoimage/nanotrasenprivatesecurity
|
|
outfit_type = /datum/outfit/nanotrasensoldiercorpse2
|
|
|
|
/datum/preset_holoimage/gorilla
|
|
nonhuman_mobtype = /mob/living/simple_animal/hostile/gorilla
|
|
|
|
/datum/preset_holoimage/corgi
|
|
nonhuman_mobtype = /mob/living/simple_animal/pet/dog/corgi
|
|
|
|
/datum/preset_holoimage/clown
|
|
outfit_type = /datum/outfit/job/clown
|
|
|
|
/obj/item/disk/holodisk/donutstation/whiteship
|
|
name = "Blackbox Print-out #DS024"
|
|
desc = "A holodisk containing the last viable recording of DS024's blackbox."
|
|
preset_image_type = /datum/preset_holoimage/engineer/ce
|
|
preset_record_text = {"
|
|
NAME Geysr Shorthalt
|
|
SAY Engine renovations complete and the ships been loaded. We all ready?
|
|
DELAY 25
|
|
PRESET /datum/preset_holoimage/engineer
|
|
NAME Jacob Ullman
|
|
SAY Lets blow this popsicle stand of a station.
|
|
DELAY 20
|
|
PRESET /datum/preset_holoimage/engineer/atmos
|
|
NAME Lindsey Cuffler
|
|
SAY Uh, sir? Shouldn't we call for a secondary shuttle? The bluespace drive on this thing made an awfully weird noise when we jumped here..
|
|
DELAY 30
|
|
PRESET /datum/preset_holoimage/engineer/ce
|
|
NAME Geysr Shorthalt
|
|
SAY Pah! Ship techie at the dock said to give it a good few kicks if it started acting up, let me just..
|
|
DELAY 25
|
|
SOUND punch
|
|
SOUND sparks
|
|
DELAY 10
|
|
SOUND punch
|
|
SOUND sparks
|
|
DELAY 10
|
|
SOUND punch
|
|
SOUND sparks
|
|
SOUND warpspeed
|
|
DELAY 15
|
|
PRESET /datum/preset_holoimage/engineer/atmos
|
|
NAME Lindsey Cuffler
|
|
SAY Uhh.. is it supposed to be doing that??
|
|
DELAY 15
|
|
PRESET /datum/preset_holoimage/engineer/ce
|
|
NAME Geysr Shorthalt
|
|
SAY See? Working as intended. Now, are we all ready?
|
|
DELAY 10
|
|
PRESET /datum/preset_holoimage/engineer
|
|
NAME Jacob Ullman
|
|
SAY Is it supposed to be glowing like that?
|
|
DELAY 20
|
|
SOUND explosion
|
|
|
|
"}
|
|
|
|
/obj/item/disk/holodisk/ruin/snowengieruin
|
|
name = "Blackbox Print-out #EB412"
|
|
desc = "A holodisk containing the last moments of EB412. There's a bloody fingerprint on it."
|
|
preset_image_type = /datum/preset_holoimage/engineer
|
|
preset_record_text = {"
|
|
NAME Dave Tundrale
|
|
SAY Maria, how's Build?
|
|
DELAY 10
|
|
NAME Maria Dell
|
|
PRESET /datum/preset_holoimage/engineer/atmos
|
|
SAY It's fine, don't worry. I've got Plastic on it. And frankly, i'm kinda busy with, the, uhhm, incinerator.
|
|
DELAY 30
|
|
NAME Dave Tundrale
|
|
PRESET /datum/preset_holoimage/engineer
|
|
SAY Aight, wonderful. The science mans been kinda shit though. No RCDs-
|
|
DELAY 20
|
|
NAME Maria Dell
|
|
PRESET /datum/preset_holoimage/engineer/atmos
|
|
SAY Enough about your RCDs. They're not even that important, just bui-
|
|
DELAY 15
|
|
SOUND explosion
|
|
DELAY 10
|
|
SAY Oh, shit!
|
|
DELAY 10
|
|
PRESET /datum/preset_holoimage/engineer/atmos/rig
|
|
LANGUAGE /datum/language/narsie
|
|
NAME Unknown
|
|
SAY RISE, MY LORD!!
|
|
DELAY 10
|
|
LANGUAGE /datum/language/common
|
|
NAME Plastic
|
|
PRESET /datum/preset_holoimage/engineer/rig
|
|
SAY Fuck, fuck, fuck!
|
|
DELAY 20
|
|
SAY It's loose! CALL THE FUCKING SHUTT-
|
|
DELAY 10
|
|
PRESET /datum/preset_holoimage/corgi
|
|
NAME Blackbox Automated Message
|
|
SAY Connection lost. Dumping audio logs to disk.
|
|
DELAY 50"}
|