diff --git a/code/modules/admin/callproc/callproc.dm b/code/modules/admin/callproc/callproc.dm index fd168b15e42..36fc9a8f9c2 100644 --- a/code/modules/admin/callproc/callproc.dm +++ b/code/modules/admin/callproc/callproc.dm @@ -1,149 +1,133 @@ - /client/proc/callproc() set category = "Debug" set name = "Advanced ProcCall" + set waitfor = 0 - if(!check_rights(R_DEBUG)) return - if(config.debugparanoid && !check_rights(R_ADMIN)) return + if(!check_rights(R_DEBUG)) + return - var/target = null + var/datum/target = null var/targetselected = 0 - - switch(alert("Proc owned by something?",, "Yes", "No", "Cancel")) - if("Yes") - targetselected=1 - switch(input("Proc owned by...", "Owner", null) as null|anything in list("Obj", "Mob", "Area or Turf", "Client")) - if("Obj") - target = input("Select target:", "Target") as null|obj in world - if("Mob") - target = input("Select target:", "Target", usr) as null|mob in world - if("Area or Turf") - target = input("Select target:", "Target", get_turf(usr)) as null|area|turf in world - if("Client") - target = input("Select target:", "Target", usr.client) as null|anything in clients - else - return - if(!target) - usr << "Proc call cancelled." - return - if("Cancel") - return - if("No") - ; // do nothing - - callproc_targetpicked(targetselected, target) - -/client/proc/callproc_target(atom/A in world) - set category = "Debug" - set name = "Advanced ProcCall Target" - - if(!check_rights(R_DEBUG)) return - if(config.debugparanoid && !check_rights(R_ADMIN)) return - - callproc_targetpicked(1, A) - -/client/proc/callproc_targetpicked(hastarget, datum/target) - - // this needs checking again here because VV's 'Call Proc' option directly calls this proc with the target datum - if(!check_rights(R_DEBUG)) return - if(config.debugparanoid && !check_rights(R_ADMIN)) return - var/returnval = null - var/procname = input("Proc name", "Proc") as null|text - if(!procname) return - - if(hastarget) - if(!target) - usr << "Your callproc target no longer exists." - return - if(!hascall(target, procname)) - usr << "\The [target] has no call [procname]()" - return - - var/list/arguments = list() - var/done = 0 - var/current = null - - while(!done) - if(hastarget && !target) - usr << "Your callproc target no longer exists." - return - switch(input("Type of [arguments.len+1]\th variable", "argument [arguments.len+1]") as null|anything in list( - "finished", "null", "text", "num", "type", "obj reference", "mob reference", - "area/turf reference", "icon", "file", "client", "mob's area", "marked datum")) - if(null) + switch(alert("Proc owned by something?",,"Yes","No")) + if("Yes") + targetselected = 1 + var/list/value = vv_get_value(default_class = VV_ATOM_REFERENCE, classes = list(VV_ATOM_REFERENCE, VV_DATUM_REFERENCE, VV_MOB_REFERENCE, VV_CLIENT)) + if (!value["class"] || !value["value"]) return + target = value["value"] + if("No") + target = null + targetselected = 0 -<<<<<<< HEAD - if("finished") - done = 1 + var/procname = input("Proc path, eg: /proc/fake_blood","Path:", null) as text|null + if(!procname) + return - if("null") - current = null + //hascall() doesn't support proc paths (eg: /proc/gib(), it only supports "gib") + var/testname = procname + if(targetselected) + //Find one of the 3 possible ways they could have written /proc/PROCNAME + if(findtext(procname, "/proc/")) + testname = replacetext(procname, "/proc/", "") + else if(findtext(procname, "/proc")) + testname = replacetext(procname, "/proc", "") + else if(findtext(procname, "proc/")) + testname = replacetext(procname, "proc/", "") + //Clear out any parenthesis if they're a dummy + testname = replacetext(testname, "()", "") - if("text") - current = input("Enter text for [arguments.len+1]\th argument") as null|text - if(isnull(current)) return - - if("num") - current = input("Enter number for [arguments.len+1]\th argument") as null|num - if(isnull(current)) return - - if("type") - current = input("Select type for [arguments.len+1]\th argument") as null|anything in typesof(/obj, /mob, /area, /turf) - if(isnull(current)) return - - if("obj reference") - current = input("Select object for [arguments.len+1]\th argument") as null|obj in world - if(isnull(current)) return - - if("mob reference") - current = input("Select mob for [arguments.len+1]\th argument") as null|mob in world - if(isnull(current)) return - - if("area/turf reference") - current = input("Select area/turf for [arguments.len+1]\th argument") as null|area|turf in world - if(isnull(current)) return - - if("icon") - current = input("Provide icon for [arguments.len+1]\th argument") as null|icon - if(isnull(current)) return - - if("client") - current = input("Select client for [arguments.len+1]\th argument") as null|anything in clients - if(isnull(current)) return - - if("mob's area") - var/mob/M = input("Select mob to take area for [arguments.len+1]\th argument") as null|mob in world - if(!M) return - current = get_area(M) - if(!current) - switch(alert("\The [M] appears to not have an area; do you want to pass null instead?",, "Yes", "Cancel")) - if("Yes") - ; // do nothing - if("Cancel") - return - - if("marked datum") - current = holder.marked_datum - if(!current) - switch(alert("You do not currently have a marked datum; do you want to pass null instead?",, "Yes", "Cancel")) - if("Yes") - ; // do nothing - if("Cancel") - return - if(!done) - arguments += current - - if(hastarget) - if(!target) - usr << "Your callproc target no longer exists." + if(targetselected && !hascall(target,testname)) + to_chat(usr, "Error: callproc(): type [target.type] has no proc named [procname].") + return + else + var/procpath = text2path(procname) + if (!procpath) + to_chat(usr, "Error: callproc(): proc [procname] does not exist. (Did you forget the /proc/ part?)") return - log_admin("[key_name(src)] called [target]'s [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].") - if(arguments.len) - returnval = call(target, procname)(arglist(arguments)) -======= + var/list/lst = get_callproc_args() + if(!lst) + return + + if(targetselected) + if(!target) + to_chat(usr, "Error: callproc(): owner of proc no longer exists.") + return + var/msg = "[key_name(src)] called [target]'s [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"]." + log_admin(msg) + //message_admins(msg) //Proccall announce removed. + admin_ticket_log(target, msg) + returnval = WrapAdminProcCall(target, procname, lst) // Pass the lst as an argument list to the proc + else + //this currently has no hascall protection. wasn't able to get it working. + log_admin("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") + //message_admins("[key_name(src)] called [procname]() with [lst.len ? "the arguments [list2params(lst)]":"no arguments"].") //Proccall announce removed. + returnval = WrapAdminProcCall(GLOBAL_PROC, procname, lst) // Pass the lst as an argument list to the proc + . = get_callproc_returnval(returnval, procname) + if(.) + to_chat(usr, .) + feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +GLOBAL_VAR(AdminProcCaller) +GLOBAL_PROTECT(AdminProcCaller) +GLOBAL_VAR_INIT(AdminProcCallCount, 0) +GLOBAL_PROTECT(AdminProcCallCount) +GLOBAL_VAR(LastAdminCalledTargetRef) +GLOBAL_PROTECT(LastAdminCalledTargetRef) +GLOBAL_VAR(LastAdminCalledTarget) +GLOBAL_PROTECT(LastAdminCalledTarget) +GLOBAL_VAR(LastAdminCalledProc) +GLOBAL_PROTECT(LastAdminCalledProc) +GLOBAL_LIST_EMPTY(AdminProcCallSpamPrevention) +GLOBAL_PROTECT(AdminProcCallSpamPrevention) + +/proc/WrapAdminProcCall(datum/target, procname, list/arguments) + if(target && procname == "Del") + to_chat(usr, "Calling Del() is not allowed") + return + + if(target != GLOBAL_PROC && !target.CanProcCall(procname)) + to_chat(usr, "Proccall on [target.type]/proc/[procname] is disallowed!") + return + var/current_caller = GLOB.AdminProcCaller + var/ckey = usr ? usr.client.ckey : GLOB.AdminProcCaller + if(!ckey) + CRASH("WrapAdminProcCall with no ckey: [target] [procname] [english_list(arguments)]") + if(current_caller && current_caller != ckey) + if(!GLOB.AdminProcCallSpamPrevention[ckey]) + to_chat(usr, "Another set of admin called procs are still running, your proc will be run after theirs finish.") + GLOB.AdminProcCallSpamPrevention[ckey] = TRUE + UNTIL(!GLOB.AdminProcCaller) + to_chat(usr, "Running your proc") + GLOB.AdminProcCallSpamPrevention -= ckey + else + UNTIL(!GLOB.AdminProcCaller) + GLOB.LastAdminCalledProc = procname + if(target != GLOBAL_PROC) + GLOB.LastAdminCalledTargetRef = "\ref[target]" + GLOB.AdminProcCaller = ckey //if this runtimes, too bad for you + ++GLOB.AdminProcCallCount + . = world.WrapAdminProcCall(target, procname, arguments) + if(--GLOB.AdminProcCallCount == 0) + GLOB.AdminProcCaller = null + +//adv proc call this, ya nerds +/world/proc/WrapAdminProcCall(datum/target, procname, list/arguments) + if(target == GLOBAL_PROC) + return call(procname)(arglist(arguments)) + else if(target != world) + return call(target, procname)(arglist(arguments)) + else + log_admin("[key_name(usr)] attempted to call world/proc/[procname] with arguments: [english_list(arguments)]") + +/proc/IsAdminAdvancedProcCall() +#ifdef TESTING + return FALSE +#else + return usr && usr.client && GLOB.AdminProcCaller == usr.client.ckey +#endif + /client/proc/callproc_datum(datum/A as null|area|mob|obj|turf) set category = "Debug" set name = "Atom ProcCall" @@ -218,12 +202,9 @@ . += "[procname] returned a list:" for(var/elem in returnedlist) . += "\n[elem]" ->>>>>>> 158d8d3... Merge pull request #5905 from kevinz000/patch-2 else - returnval = call(target, procname)() - else - log_admin("[key_name(src)] called [procname]() with [arguments.len ? "the arguments [list2params(arguments)]" : "no arguments"].") - returnval = call(procname)(arglist(arguments)) + . = "[procname] returned an empty list" + . += "" - usr << "[procname]() returned: [isnull(returnval) ? "null" : returnval]" - feedback_add_details("admin_verb","APC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + else + . = "[procname] returned: [!isnull(returnval) ? returnval : "null"]"