local timer = require("timer") local state = require("state") local SS13 = {} __SS13_signal_handlers = __SS13_signal_handlers or {} SS13.SSlua = dm.global_vars.SSlua SS13.global_proc = "some_magic_bullshit" SS13.state = state.state function SS13.get_runner_ckey() return SS13.state.ckey_last_runner end function SS13.get_runner_client() return dm.global_vars.GLOB.directory[SS13.get_runner_ckey()] end function SS13.ispath(thing, path) return dm.global_procs._ispath(thing, path) == 1 end function SS13.type(typepath) if type(typepath) == "string" then return dm.global_procs._text2path(typepath) elseif SS13.ispath(typepath) then return typepath else return nil end end function SS13.istype(thing, type) return dm.global_procs._istype(thing, SS13.type(type)) == 1 end function SS13.typecacheof(string_types) local types = {} for _, path in string_types do if path ~= nil then table.insert(types, SS13.type(path)) end end return dm.global_procs.typecacheof(types) end function SS13.is_type_in_typecache(thing, typecache) return dm.global_procs._is_type_in_typecache(thing, typecache) == 1 end function SS13.typesof(type, subtypes_only) return dm.global_procs._typesof(SS13.type(type), subtypes_only) end function SS13.get_turf(thing) return dm.global_procs._get_step(thing, 0) end function SS13.get_area(thing) if SS13.istype(thing, "/area") then return thing else local turf = SS13.get_turf(thing) -- don't bother with SS13.is_valid, turfs don't get destroyed if dm.is_valid_ref(turf) then return turf.loc end end return nil end SS13.new = dm.new function SS13.qdel(datum) if SS13.is_valid(datum) then dm.global_procs.qdel(datum) return true end return false end function SS13.is_valid(datum) return dm.is_valid_ref(datum) and not datum.gc_destroyed end function SS13.check_tick(high_priority) local tick_limit = if high_priority then 95 else dm.global_vars.Master.current_ticklimit if dm.world.tick_usage > tick_limit then sleep() end end function SS13.await(thing_to_call, proc_to_call, ...) if not SS13.istype(thing_to_call, "/datum") then thing_to_call = SS13.global_proc end if thing_to_call == SS13.global_proc then proc_to_call = "/proc/" .. proc_to_call end local promise = SS13.new("/datum/promise", thing_to_call, proc_to_call, ...) while promise.status == 0 do sleep() end return promise.return_value, promise.runtime_message end local function signal_handler(data, ...) local output = 0 for func, _ in data.functions do local result = func(...) if type(result) == "number" then output = bit32.bor(output, math.floor(result)) end end return output end local function create_qdeleting_callback(datum) local callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first") callback:RegisterSignal(datum, "parent_qdeleting", "Invoke") local path = { "__SS13_signal_handlers", dm.global_procs.WEAKREF(datum), "parent_qdeleting", "handler", } callback.arguments = { path } local handler_data = { callback = callback, functions = {} } handler_data.handler = function(source, ...) local result = signal_handler(handler_data, source, ...) for signal, signal_data in __SS13_signal_handlers[source] do signal_data.callback:UnregisterSignal(source, signal) end __SS13_signal_handlers[source] = nil return result end __SS13_signal_handlers[datum]["parent_qdeleting"] = handler_data end function SS13.register_signal(datum, signal, func) if type(func) ~= "function" then return end if not SS13.istype(datum, "/datum") then return end if not SS13.is_valid(datum) then error("Tried to register a signal on a deleted datum", 2) end if not __SS13_signal_handlers[datum] then __SS13_signal_handlers[datum] = {} -- Turfs don't remove their signals on deletion. if not SS13.istype(datum, "/turf") then create_qdeleting_callback(datum) end end local handler_data = __SS13_signal_handlers[datum][signal] if not handler_data then handler_data = { callback = nil, functions = {} } local callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first") callback:RegisterSignal(datum, signal, "Invoke") local path = { "__SS13_signal_handlers", dm.global_procs.WEAKREF(datum), signal, "handler", } callback.arguments = { path } handler_data.callback = callback handler_data.handler = function(...) return signal_handler(handler_data, ...) end __SS13_signal_handlers[datum][signal] = handler_data end handler_data.functions[func] = true return true end function SS13.unregister_signal(datum, signal, func) if not (func == nil or type(func) == "function") then return end if not __SS13_signal_handlers[datum] then return end local handler_data = __SS13_signal_handlers[datum][signal] if not handler_data then return end if func == nil then if signal == "parent_qdeleting" then handler_data.functions = {} else handler_data.callback:UnregisterSignal(datum, signal) __SS13_signal_handlers[datum][signal] = nil end else handler_data.functions[func] = nil if not (#handler_data.functions or (signal == "parent_qdeleting")) then handler_data.callback:UnregisterSignal(datum, signal) __SS13_signal_handlers[datum][signal] = nil end end end return SS13