Files
Bubberstation/code/modules/wiremod/components/admin/signal_handler/signal_handler.dm
Y0SH1M4S73R b7ed43d7a8 Adds a Datum port type for Admin Circuits (#61582)
Admin circuit components were limited in their utility due to the setvar, getvar, proccall, and signal handler components only being able to operate on atoms. I have improved them by adding the datum datatype, which is used exclusively by the aforementioned components in place of the atom datatype their target port currently uses. Furthermore, an option for the expected output type has been added to the getvar and proccall components. This option defaults to any.
2021-09-22 08:04:05 +01:00

204 lines
7.0 KiB
Plaintext

#define COMP_SIGNAL_HANDLER_GLOBAL "Global"
#define COMP_SIGNAL_HANDLER_OBJECT "Object"
/**
* # Signal Handler Component
*
* A component that registers signals on events and listens for them.
*/
/obj/item/circuit_component/signal_handler
display_name = "Signal Handler"
desc = "A component that listens for signals on an object. Registering a new object will automatically unregister the old."
circuit_flags = CIRCUIT_FLAG_ADMIN|CIRCUIT_FLAG_INSTANT
/// Whether it is a global or object signal
var/datum/port/input/option/signal_handler_options
/// The list of signal IDs that can be selected as an option.
var/datum/port/input/option/signal_id
var/list/signal_map
/// Entity to register the signal on
var/datum/port/input/target
/// Registers the signal
var/datum/port/input/register
/// Unregisters the signal from the current registered entity.
var/datum/port/input/unregister
/// The custom signal ports from the current signal type. Used for saving and loading.
var/list/signal_ports
/// The custom input from the current signal type.
var/list/datum/port/input/input_signal_ports = list()
/// The custom output from the current signal type.
var/list/datum/port/output/output_signal_ports = list()
/// The entity received from the event.
var/datum/port/output/entity
/// The event has been triggered
var/datum/port/output/event_triggered
/// The current entity that has the signal registered on it
var/datum/weakref/current_registered_entity
/// The current registered signal
var/registered_signal
/// Whether it is a custom signal id or not.
var/custom_signal = FALSE
/obj/item/circuit_component/signal_handler/populate_options()
var/static/list/component_options = list(
COMP_SIGNAL_HANDLER_OBJECT,
COMP_SIGNAL_HANDLER_GLOBAL,
)
signal_handler_options = add_option_port("Signal Handler Options", component_options, trigger = null)
signal_id = add_option_port("Signal ID", GLOB.integrated_circuit_signal_ids, trigger = null)
signal_map = GLOB.integrated_circuit_signal_ids
/obj/item/circuit_component/signal_handler/populate_ports()
register = add_input_port("Register", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/register_signals)
unregister = add_input_port("Unregister Current", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/unregister_signals)
add_source_entity()
event_triggered = add_output_port("Triggered", PORT_TYPE_SIGNAL, order = 2)
/obj/item/circuit_component/signal_handler/proc/add_source_entity()
if(target)
remove_input_port(target)
if(entity)
remove_output_port(entity)
target = add_input_port("Target", PORT_TYPE_DATUM, order = 1, trigger = null)
entity = add_output_port("Source Entity", PORT_TYPE_DATUM, order = 0)
/obj/item/circuit_component/signal_handler/save_data_to_list(list/component_data)
. = ..()
component_data["signal_id"] = signal_id.value
component_data["signal_port_data"] = signal_ports
/obj/item/circuit_component/signal_handler/load_data_from_list(list/component_data)
signal_id.set_value(component_data["signal_id"], force = TRUE)
registered_signal = signal_id.value
load_new_ports(component_data["signal_port_data"])
custom_signal = TRUE
return ..()
/obj/item/circuit_component/signal_handler/pre_input_received(datum/port/input/port)
if(signal_id == port)
custom_signal = FALSE
if(current_registered_entity)
unregister_signals(port)
var/last_registered_signal = registered_signal
registered_signal = signal_id.value
if(registered_signal != last_registered_signal)
var/list/data = signal_map[registered_signal]
if(data)
load_new_ports(data)
unregister_signals(port)
if(signal_handler_options == port)
set_signal_options(port)
/obj/item/circuit_component/signal_handler/proc/set_signal_options(datum/port/input/port)
CIRCUIT_TRIGGER
switch(signal_handler_options.value)
if(COMP_SIGNAL_HANDLER_GLOBAL)
signal_id.possible_options = GLOB.integrated_circuit_global_signal_ids
signal_map = GLOB.integrated_circuit_global_signal_ids
remove_output_port(entity)
remove_input_port(target)
if(COMP_SIGNAL_HANDLER_OBJECT)
signal_id.possible_options = GLOB.integrated_circuit_signal_ids
signal_map = GLOB.integrated_circuit_signal_ids
add_source_entity()
if(!custom_signal)
signal_id.set_value(null, TRUE)
unregister_signals()
/obj/item/circuit_component/signal_handler/proc/register_signals(datum/port/input/port)
CIRCUIT_TRIGGER
if(current_registered_entity)
unregister_signals(port)
var/datum/target_datum = target.value
if(signal_handler_options.value == COMP_SIGNAL_HANDLER_GLOBAL)
target_datum = SSdcs
if(target_datum)
RegisterSignal(target_datum, registered_signal, .proc/handle_signal_received)
current_registered_entity = WEAKREF(target_datum)
/obj/item/circuit_component/signal_handler/proc/load_new_ports(list/ports_to_load)
for(var/datum/port/input/input_port as anything in input_signal_ports)
remove_input_port(input_port)
for(var/datum/port/output/output_port as anything in output_signal_ports)
remove_output_port(output_port)
input_signal_ports = list()
output_signal_ports = list()
signal_ports = ports_to_load
for(var/list/data in signal_ports)
if(data["is_response"])
var/datum/port/input/bitflag_input = add_input_port(data["name"], PORT_TYPE_SIGNAL, order = 1, trigger = .proc/handle_bitflag_received)
input_signal_ports[bitflag_input] = data["bitflag"]
else
output_signal_ports += add_output_port(data["name"], data["type"], order = 1)
/obj/item/circuit_component/signal_handler/proc/unregister_signals(datum/port/input/port)
CIRCUIT_TRIGGER
var/datum/registered_datum = current_registered_entity?.resolve()
if(!registered_datum)
return
UnregisterSignal(registered_datum, registered_signal)
current_registered_entity = null
/obj/item/circuit_component/signal_handler/proc/handle_signal_received(...)
SIGNAL_HANDLER
var/list/arguments = args.Copy()
// usr is not supposed to be defined whilst these execute, which it can be for some signal IDs.
// Especially if you try to proccall something - it'll fail because of this reason.
// No other way to solve this problem without refactoring proccall code, but it's admin tooling so it's whatever.
var/temp_usr = usr
usr = null
SScircuit_component.queue_instant_run()
var/first_arg = popleft(arguments)
if(entity)
entity.set_output(first_arg)
for(var/datum/port/output/port as anything in output_signal_ports)
port.set_output(popleft(arguments))
event_triggered.set_output(COMPONENT_SIGNAL)
var/list/output = SScircuit_component.execute_instant_run()
usr = temp_usr
if(!output)
message_admins("[parent.get_creator_admin()] took too much CPU time trying to handle a signal. Reduce the amount of circuit components attached to your [name] circuit component.")
return
return output["bitflag"] || NONE
/obj/item/circuit_component/signal_handler/proc/handle_bitflag_received(datum/port/input/port, list/return_values)
CIRCUIT_TRIGGER
if(!return_values)
return
if(!return_values["bitflag"])
return_values["bitflag"] = NONE
return_values["bitflag"] |= input_signal_ports[port]
#undef COMP_SIGNAL_HANDLER_GLOBAL
#undef COMP_SIGNAL_HANDLER_OBJECT